To put it simply, I'm trying to create one stream that links to a file std::ofstream outFile{pathToFile, std::ios_base::app};
. This file is a log file that, ideally, would receive copies of both stderr and stdout. When an error would occur, for example, the error would be printed in the console and in the file.
I've tried using freopen(pathToFile, "a ", stderr);
as well as std::cerr.rdbuf(outFile.rdbuf());
however, both of these completely redirect the output, similar to a pipe in bash. I also want to see the error in the console.
Being somewhat new to C streams, I'm not quite sure how I would achieve this. The way I would see it being done in another language would be "subscribing" to stderr, so my original stream would be notified everytime stderr changes and update itself. Another way would be to override stderr, log to my file and call the original one, but since stderr is usually not called by the programmer itself, I'm not sure how I could do that.
It should be noted that I'm using windows, so I don't have access to unistd.h
. I would also like to avoid using STL
or third party libraries.
CodePudding user response:
The IOStreams internally use a std::streambuf
to actually write (or read) characters. If you just want to redirect all characters written to another stream, you can just redirect the respective stream buffer. You should restore the original stream buffer eventually, though, as the streams are flushed on destruction and the life time of the stream buffers matter. For example
#include <iostream>
#include <fstream>
struct redirect {
std::ostream& d_stream;
std::streambuf* d_orig;
redirect(std::ostream& out, std::ostream& to)
: d_stream(out)
, d_orig(out.rdbuf(to.rdbuf())) {
}
~redirect() { this->d_stream.rdbuf(this->d_orig); }
};
int main() {
std::ofstream log("my-log.txt");
redirect rcout(std::cout, log);
redirect rcerr(std::cerr, log);
std::cout << "hello, ";
std::cerr << "world!\n";
}
If you also want to the redirected stream to appear on the original stream, you can use a "teestream
" which uses a stream buffer copying each character to two different stream buffers (I have posted multiple versions of such a stream in the past in multiple place, including on stackoverflow).