Check what output is written to standard output - c++

I want to check whether output is written to the standard output (through cout) in a certain part of my program.
What I found is a way to block any output by changing the streambuf of cout. (here:C++: Redirecting STDOUT). That is interesting and first I thought it might help. I found the following code example (source: answer to C++: Redirecting STDOUT)
// Redirect cout.
streambuf* oldCoutStreamBuf = cout.rdbuf();
ostringstream strCout;
cout.rdbuf( strCout.rdbuf() );
// This goes to the string stream.
cout << "Hello, World!" << endl;
// Restore old cout.
cout.rdbuf( oldCoutStreamBuf );
// Will output our Hello World! from above.
cout << strCout.str();
So I can just check whether strCout.str() is a string with 1 or more characters by checking its size.
But what if I do not want to delay the output significantly? So I do not want to save all output in my own ostringstream, wait until I checked whether there was output at the end of my program and then print all the output shortly before my programm ends. I just want to know, whether there was output in a certain part of my program.
Example:
main {
bool wasthereoutput=false;
function1();
function2();
startoutputcheckhere();
function3();
function4();
endoutputcheckhere();
therewasoutput=wasthereoutput();
if therewasoutput{
//do something
}
I don't want to change anything in function3 or function4. I do not want to delay any output generated by those functions until i call endoutputcheckhere() or even wasthereoutput(). I just want to know if there was any output going to std output through cout.

You can create a stream buffer which both collects the written characters for later and also forwards them to another stream buffer, e.g., the one used by std::cout. A simple implementation of this approach could look like this:
class savebuf:
public std::streambuf {
std::streambuf* sbuf;
std::string save;
int overflow(int c) {
if (!traits_type::eq_int_type(c, traits_type::eof()) {
save.push_back(traits_type::to_char_type(c);
return sbuf->sputc(c);
}
else {
return traits_type::not_eof(c);
}
}
int sync() { return sbuf->pubsync(); }
public:
savebuf(std::streambuf* sbuf): sbuf(sbuf) {}
std::string str() const { return save; }
};
int main() {
std::streambuf* coutbuf = std::cout.rdbuf();
savebuf sbuf(coutbuf);
std::cout.rdbuf(&sbuf);
std::cout << "Hello, world\n";
std::cout.rdbuf(coutbuf); // restore the original stream buffer
std::cout << "saved \"" << sbuf.str() << "\"\n";
}
Note that you should restore std::cout's stream buffer as the stream buffer is flushed (i.e. pubsync() is called on it) when std::cout is sort of destroyed.

Related

C/C++ stdout/stderr catch

I try to find a way to catch the standard outputs in a C++ application. This app is quite large, using third parties and may use outputs in both C or C++ ways (assuming there are std::cout calls as well as printf calls)
we can simulate by something like:
void MyAwesomeApp()
{
std::cout << "I am starting" << std::endl;
std::cerr << "Getting a warning!\n";
printf("With old style print\n");
std::cout << "That's all folk!\n";
}
I already tried 2 approachs:
1. std::streambuf
class MyStreambuf : public std::streambuf {
public:
explicit MyStreambuf(const std::string& fileName = "" )
{
if (!fileName.empty())
{
_file1.open(std::filesystem::temp_directory_path() / fileName,std::ios::out);
_file2.open(std::filesystem::current_path() / fileName, std::ios::out);
}
if (_file1.is_open())
{
saveOut = std::cout.rdbuf();
std::cout.rdbuf(this);
saveErr = std::cerr.rdbuf();
std::cerr.rdbuf(this);
}
}
const std::string& GetOutput()const{return saveStr;}
~MyStreambuf() override
{
if (saveOut) std::cout.rdbuf(saveOut);
if (saveErr) std::cerr.rdbuf(saveErr);
_file1.close();
_file2.close();
}
protected:
std::streamsize xsputn(char_type const* s, std::streamsize count) override {
if (_file1.is_open()) _file1.write(s,count);
saveStr.append(s, static_cast<std::size_t>(count));
// .... DO SOME MODIFICATIONS ....
if (_file2.is_open()) _file2.write(s,count);
return count;
}
private:
std::ofstream _file1{};
std::ofstream _file2{};
std::string saveStr{};
std::streambuf* saveOut = nullptr;
std::streambuf* saveErr = nullptr;
};
So I can call, for example:
int main()
{
MyStreambuf outbuf;
MyAwesomeApp();
return !outbuf.GetOutput().empty()
}
I can have the 2 files filled as well as the string, but without the content of the printf call (that remains in the console)
2. dup2
using dup2 I can redirect all the stdout (and stderr) output to a given file. so I get all the contents of std::cout AND printf. but I can Only do that in a file that I have to read (an parse) at the end.
The application may run for a long time And we want to parse outputs during execution not waiting for the end.
Is it possible to have the benefits of the streambuf approach, but capable of catching also the printf outputs?

Force print to terminal (std::cout is being piped)

Context:
I'm editing a small piece of a large program. This large program is controlling std::cout and rerouting it so that a basic piece of code like:
std::cout << "I want to see the light of the terminal!" << std::endl;
Does not display anything to the user.
Question:
How can I get something to print directly to the terminal when my standard output/error is being rerouted? (If possible)
Other notes:
I realize that I could edit the larger program, but I'm looking to use this printout for some early diagnostics before more fully integrating my code into the program. Having to mess with how the program routes the output would really extend the development cycle.
I am also currently writing to a file as a workaround but that's slightly less desirable and frankly I would like to know how to do this in the future.
I think you can do it following these steps:
Save the redirected buffer
Change buffer to console
Get your job done
Again set buffer to the saved buffer in step 1
For example
#include <sstream>
#include <iostream>
void print_to_console() {
std::cout << "Hello from print_to_console()" << std::endl;
}
void foo(){
std::cout<<"hello world"<<std::endl;
print_to_console(); // this could be printed from anything
}
int main()
{
std::stringstream ss;
//change the underlying buffer and save the old buffer
auto old_buf = std::cout.rdbuf(ss.rdbuf());
foo(); //all the std::cout goes to ss
std::cout.rdbuf(old_buf); //reset
std::cout << "<redirected-output>\n"
<< ss.str()
<< "</redirected-output>" << std::endl;
}
I haven't tested it. I took the idea and example from this accepted answer.
For convenience, you can just write a function to print in console. This function will take care of the redirection and printing.
Write to stdout and read from stdin (both are FILE descriptors).
You can wrap them in stream classes if you wish.. IE: Using streambuf and iostreamto get the same functionality as cout.
#include <iostream>
int main(int argc, const char * argv[]) {
const char* data = "DATA TO PRINT";
fwrite(data, strlen(data), sizeof(char), stdout);
return 0;
}
Small example:
#include <iostream>
class stream : public std::streambuf
{
private:
int_type overflow(int_type c = traits_type::eof());
public:
stream() {}
virtual ~stream() {}
stream(const stream& other) = delete;
stream& operator = (const stream& other) = delete;
};
stream::int_type stream::overflow(stream::int_type c)
{
if (c != traits_type::eof())
{
fwrite(&c, 1, sizeof(c), stdout);
}
return c;
}
class mcout : public std::ostream
{
public:
mcout() : std::ostream(0), sbuf() {init(&sbuf);}
virtual ~mcout() {}
private:
stream sbuf;
} mcout;
int main(int argc, const char * argv[]) {
mcout << "HELLO\n";
return 0;
}

Date in log file using ofstream

Below is the code I have to write every time I want to include the date in my log file at the moment. I'm looking for a way to not have to write my CurrentDateToString() everytime I want to write something in my file.
ofstream log;
log.open("test.log", ios_base::app);
log << CurrentDateToString() << " | " << "first line" << endl;
log << CurrentDateToString() << " | " << "second line" << endl;
log.close();
And here is my CurrentDateToString() function:
// convert date to formatted string
string CurrentDateToString()
{
time_t rawtime;
struct tm* timeInfo;
char buffer[80];
time(&rawtime);
timeInfo = localtime(&rawtime);
strftime(buffer, 80, "%Y-%m-%d %I:%M:%S", timeInfo);
string dateString(buffer);
return dateString;
}
The goal here is to be able to write those lines instead of the current lines I'm writing:
log << "first line" << endl;
log << "second line" << endl;
Do I have to write a log class and overload operator<< or is there another way to do it ?
The way to implement a stream which automagically adds (or removes) characters, e.g., adding a date, is to create a filtering stream buffer. You'd derive a class from std::streambuf which massages the characters it receives into the necessary form and then forwards them to an underlying stream buffer.
For your use of adding a date at the start of the line you'd simply observe newline characters being received and set a flag need_date if there is a newline. When a character is being written while need_date is set, the date is written and the flag is cleared.
Here is how that could look for your date:
#include <streambuf>
class logbuf
: public std::streambuf {
std::streambuf* sbuf;
bool need_date{true};
using traits_type = std::char_traits<char>;
int overflow(int c) override {
if (c != traits_type::eof()) {
if (need_date) {
std::string date{CurrentDateToString()};
this->sbuf->sputn(date.c_str(), date.size());
need_date = false;
}
if (c == '\n') {
need_date = true;
}
return this->sbuf->sputc(c);
}
else {
return traits_type::not_eof(c);
}
}
int sync() override { return this->sbuf->pubsync(); }
public:
logbuf(std::streambuf* sbuf): sbuf(sbuf) {}
};
The virtual function overflow() is called every time there is no space in the stream buffer's buffer. Since there is no output buffer set up that happens for each character (performance can be improved by adding an override for xsputn() and/or adding buffering). The function sync() is called every time the stream is flushed. Since nothing is buffered, the flush request is simply forwarded to the underlying stream buffer.
Below is a simple demo using this stream buffer. The creation of a suitable underlying stream buffer, e.g., a std::filebuf, and an std::ostream can be packaged into a class derived from std::ostream.
#include <iostream>
int main()
{
logbuf sbuf(std::cout.rdbuf());
std::ostream logout(&sbuf);
logout << "hello\nwordl\n";
logout << "\n";
logout << "goodbye\n";
}

How to override cout in C++?

I have a requirement, I need to use printf and cout to display the data into console and file as well.
For printf I have done it but for cout I am struggling, how to do it?
#ifdef _MSC_VER
#define GWEN_FNULL "NUL"
#define va_copy(d,s) ((d) = (s))
#else
#define GWEN_FNULL "/dev/null"
#endif
#include <iostream>
#include <fstream>
using namespace std;
void printf (FILE * outfile, const char * format, ...)
{
va_list ap1, ap2;
int i = 5;
va_start(ap1, format);
va_copy(ap2, ap1);
vprintf(format, ap1);
vfprintf(outfile, format, ap2);
va_end(ap2);
va_end(ap1);
}
/* void COUT(const char* fmt, ...)
{
ofstream out("output-file.txt");
std::cout << "Cout to file";
out << "Cout to file";
}*/
int main (int argc, char *argv[]) {
FILE *outfile;
char *mode = "a+";
char outputFilename[] = "PRINT.log";
outfile = fopen(outputFilename, mode);
char bigfoot[] = "Hello
World!\n";
int howbad = 10;
printf(outfile, "\n--------\n");
//myout();
/* then i realized that i can't send the arguments to fn:PRINTs */
printf(outfile, "%s %i",bigfoot, howbad); /* error here! I can't send bigfoot and howbad*/
system("pause");
return 0;
}
I have done it in COUT(caps, the commented part for the code above) . But I want to use normal std::cout, so how can I override it. And it should work for both sting and variables like
int i = 5;
cout << "Hello world" << i <<endl;
Or are there anyway to capture stdout data, so that they can be easily written into file and console as well.
If you have another stream buffer, you can just replace std::cout's:
std::cout.rdbuf(some_other_rdbuf);
See http://en.cppreference.com/w/cpp/io/basic_ios/rdbuf.
You can swap the underlying buffers. Here is that done facilitated through RAII.
#include <streambuf>
class buffer_restore
{
std::ostream& os;
std::streambuf* buf;
public:
buffer_restore(std::ostream& os) : os(os), buf(os.rdbuf())
{ }
~buffer_restore()
{
os.rdbuf(buf);
}
};
int main()
{
buffer_restore b(std::cout);
std::ofstream file("file.txt");
std::cout.rdbuf(file.rdbuf());
// ...
}
Overriding the behaviour of std::cout is a really bad idea as other developers will have a hard time understanding that the use of std::cout doesn't behave as usual.
Make your intention clear with a simple class
#include <fstream>
#include <iostream>
class DualStream
{
std::ofstream file_stream;
bool valid_state;
public:
DualStream(const char* filename) // the ofstream needs a path
:
file_stream(filename), // open the file stream
valid_state(file_stream) // set the state of the DualStream according to the state of the ofstream
{
}
explicit operator bool() const
{
return valid_state;
}
template <typename T>
DualStream& operator<<(T&& t) // provide a generic operator<<
{
if ( !valid_state ) // if it previously was in a bad state, don't try anything
{
return *this;
}
if ( !(std::cout << t) ) // to console!
{
valid_state = false;
return *this;
}
if ( !(file_stream << t) ) // to file!
{
valid_state = false;
return *this;
}
return *this;
}
};
// let's test it:
int main()
{
DualStream ds("testfile");
if ( (ds << 1 << "\n" << 2 << "\n") )
{
std::cerr << "all went fine\n";
}
else
{
std::cerr << "bad bad stream\n";
}
}
This provides a clean interface and outputs the same for both the console and the file.
You may want to add a flush method or open the file in append mode.
I assume you have some code using std::cout and printf which you cannot modify, otherwise the most simple way to solve your problem would be to write to a different stream from cout and use fprintf rather than or in conjunction with printf.
By following that approach you could define both a new stream class that actually wrote both to standard output and to a given file, as well as a function that combined calls to both printf and fprintf.
However a much simpler approach is to use the tee program, originally from UNIX, which copies its input both to output and to a given file. With that you could simply call your program in this way:
your_program | tee your_log_file
Answers to this question lead to a few alternative implementations available for Windows. Personally I always install cygwin on my PC's to have UNIX/Linux utilities available.
If i guess correctly you want to log everything that goes to the output also into a file.
What you want is an observer pattern.
Replace all direct logging in your code with calls to a new relay.
The logging relay sends your messages to the observers.
One of your observers loggs the message to the screen.
The other one loggs to the file.
Avoid making your relay a singleton if possible.
This suggestion only works if you can edit all of your source files.
std::cout writes to stdout file you can do the following on Linux and Windows
#include <stdio.h>
#include <iostream>
int main()
{
freopen("test.txt", "w", stdout);
std::cout << "Hello strange stdout\n";
}
to change it back use the following taken from here
#include <stdio.h>
#include <stdlib.h>
void main(void)
{
FILE *stream ;
if((stream = freopen("file.txt", "w", stdout)) == NULL)
exit(-1);
printf("this is stdout output\n");
stream = freopen("CON", "w", stdout);
printf("And now back to the console once again\n");
}
Note: The latter is windows only
cout is normally implemented as an object instance so you can't override it in the way that you would overload / override a function or a class.
Your best bet is not to fight that - yes you could build a my_cout and #define cout my_cout but that would make your code obtuse.
For readability I'd leave cout as it is. It's a standard and everyone knows what it can and can't do.
Try using a macro - something like this (you'll need to add the includes) :
#define MY_COUT(theos,printThis) { cout << printThis ; theos << printThis; }
void test()
{
ofstream myos;
myos.open("testfile", ios::trunc|ios::out);
int i = 7;
MY_COUT(myos, "try this numbers" << i << i + 1 << endl);
myos.close()
}
There's already a Boost class for this: tee

Use cout or cerr to output to console after it has been redirected to file

Redirecting cout or cerr to a file is easy enough. I can use this to redirect third party output to a file. However, after I have redirected the third party output to a file, how do I then use cout myself to output to the console?
I'm a great fan of RAII, so I once wrote this small helper class. It will redirect the stream until it goes out of scope, at which point it restores the original buffer. Quite handy. :)
class StreamRedirector {
public:
explicit StreamRedirector(std::ios& stream, std::streambuf* newBuf) :
savedBuf_(stream.rdbuf()), stream_(stream)
{
stream_.rdbuf(newBuf);
}
~StreamRedirector() {
stream_.rdbuf(savedBuf_);
}
private:
std::streambuf* savedBuf_;
std::ios& stream_;
};
Can be used like this:
using namespace std;
cout << "Hello stdout" << endl;
{
ofstream logFile("log.txt");
StreamRedirector redirect(cout, logFile.rdbuf());
cout << "In log file" << endl;
}
cout << "Back to stdout" << endl;
You save the buffer and restore it later:
std::streambuf *buf = std::cout.rdbuf(); //save
// Do other stuff
std::cout.rdbuf(buf); // restore