1

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.

10
  • Should be fairly simple to this do with tee. Commented Apr 8, 2019 at 12:23
  • Just write the input you receive to your file, as well as the output you write? Yes it might be a little duplication of code, but it will make it easier to format the logging as you please or to someday use a nice existing logging framework. Commented Apr 8, 2019 at 12:24
  • Otherwise, you might want to go through the list of "Related" question listed in the right-side column here. Commented Apr 8, 2019 at 12:25
  • 1
    @PaulR In fact, I was originally looking for a solution within C++ but I 'tee' might work just fine! Commented Apr 8, 2019 at 12:33
  • 1
    @PaulR using 'tee' was the most reasonable solution I found so if you (or anyone else) is willing to make an answer from it, I will accept it! Commented Apr 8, 2019 at 12:56

2 Answers 2

1

Option 1:

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.

Option 2:

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for your answer! Option 2 is more along the lines of what I originally intended to do; but now I do believe, that option one is more elegant in the context of my application. This, however, does not take away from the usefulness of your answer to other readers!
0

It should be fairly simple to this do with tee. This would allow you to maintain any existing redirection while also sending stdin/stdout elsewhere (to files in your case). This also avoids having to make any modifications to your existing code.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.