Reputation: 362
Is there a (ideally simple and elegant) way to log stdin
and stdout
?
Note, that I do not intend to redirect the streams. I want the standard streams to remain functional to communicate with other software while also writing all inter-process communication to some file.
Upvotes: 1
Views: 1501
Reputation: 8475
As @PaulR suggests, you can use an external process such as tee (on Linux/Mac/Unix), or write your own process to read from stdin in a loop and write to stdout and another file.
I have done this many years ago with std::basic_ios::rdbuf for std::cout
. All one has to do is to define a class (see std::filebuf
, and std::streambuf
):
class tee_buf : public std::filebuf {
public:
// Not an owing pointer
tee_buf(std::streambuf * other_stream)
: m_other_stream(other_stream) {}
void swap( tee_buf& rhs );
// No need to override open/close since we need to manage only the file.
// The open/close calls don't touch the other_stream.
protected:
int_type overflow(int_type c = traits_type::eof()) override;
// The parent calls this->overflow(), but then still need to call
// m_other_stream->sync(). This is problematic since m_other_stream
// gets flushed twice.
int sync() override;
pos_type seekoff( off_type off,
std::ios_base::seekdir dir,
std::ios_base::openmode which) override {
return pos_type(off_type(-1)); // ???
}
pos_type seekpos( pos_type sp,
std::ios_base::openmode which) override {
return pos_type(off_type(-1)); // ???
}
....
This is more efficient for intensive IO as it avoids the middle-man. But in most cases the tee solution is simpler and preferable. If performance is an issue (which in most cases it isn't), then it may be possible to make both stream buffers share a single memory buffer. It may also be possible to use async IO to write to both streams in parallel.
Usage with memory leak:
std::cout.rdbuf(new tee_buf(std::cout.rdbuf());
Usage without memory leak:
Write a RAII class to contain the tee_buf
, to save the original and set the new std::cout.rdbuf()
. Upon destruction restore the state of std::cout.rdbuf()
. Make a single instance of this class, which will do the dirty work upon its construction and destruction.
As for the C style stdout
: I don't believe that there is a way to override its behavior. At most it is possible to play with buffer memory, but that is not enough to get the desired functionality. With stdout
the only thing one can do is use a tee
-like solution.
Upvotes: 1