Reputation: 6501
I'm working on a program that makes heavy use of "cout << strSomething;" to log information to the console. I need to modify the program so that all console output goes to both the console AND a file. Although I can modify the "cout <<" in our code, there are several large third party libraries that also use "cout <<"; those libraries cannot be modified due to their licenses - so modifying all references to "cout <<" is not a solution. Also, the use of "wtee.exe" isn't possible due to the manner in which the command lines are executed.
I am using Visual Studio 2008. I've seen the posting at Google Groups: redirect cout to file, which appears to do EXACTLY what I want to do. The only problem is that the code won't compile. I get C2248 errors "cannot access protected member" on the ->overflow() and ->sync() method calls.
Would anyone know how to get this code to compile? Or an alternate way of redirecting cout to both console and file simultaneously?
Upvotes: 9
Views: 11585
Reputation: 31
This easily extends to additional streams.
OstreamFork.hpp -- Distribute data to 2 streams simultaneously
#include <iomanip>
#include <fstream>
#include <iostream>
using namespace std ;
class ostreamFork // Write same data to two ostreams
{
public:
ostream& os1 ;
ostream& os2 ;
ostreamFork( ostream& os_one , ostream& os_two )
: os1( os_one ) ,
os2( os_two )
{}
} ;
// For data: int, long , ...
template <class Data>
ostreamFork& operator<<( ostreamFork& osf , Data d )
{
osf.os1 << d ;
osf.os2 << d ;
return osf ;
}
// For manipulators: endl, flush
ostreamFork& operator<<( ostreamFork& osf , ostream& (*f)(ostream&) )
{
osf.os1 << f ;
osf.os2 << f ;
return osf ;
}
// For setw() , ...
template<class ManipData>
ostreamFork& operator<<( ostreamFork& osf , ostream& (*f)(ostream&, ManipData ) )
{
osf.os1 << f ;
osf.os2 << f ;
return osf ;
}
TestOstreamFork.cpp:
#include "stdafx.h"
#include <fstream>
using namespace std ;
#include "ostreamFork.hpp"
int main(int argc, char* argv[])
{
ofstream file( "test2.txt" ) ;
ostreamFork osf( file , cout ) ;
for ( int i = 0 ; i < 10 ; i++ )
{
osf << i << setw(10) << " " << 10*i << endl ;
}
return 0 ;
}
Output to both cout and test2.txt:
0 0
1 10
2 20
3 30
4 40
5 50
6 60
7 70
8 80
9 90
Upvotes: 3
Reputation: 322
Sorry to warm this up so late, but this here should be a solution with redirection of cout to a teebuffer based on Dietmar Kühl's solution on Google groups.
Usage is simply
GetSetLog log("myfile.log");
During the lifetime of the object "log" everything will be written to both cout/cerr and file
https://sourceforge.net/p/getset/code/ci/master/tree/GetSet/GetSetLog.hxx
Upvotes: 0
Reputation: 3411
you can just use a wrapper class to do so, somthing like this
#include <iostream>
#include <fstream>
...
class streamoutput
{
std::ofstream fileoutput;
public:
streamoutput(char*filename){
fileoutput.open(filename);
}
~streamoutput(){
fileoutput.close();
}
template<class TOut> streamoutput& operator <<(const TOut& data)
{
fileoutput << data;
std::cout << data;
return this;
}
};
extern streamoutput cout("logfile.log");
declare cout like that and just change all your #include <iostream>
to include this wrapper (remeber cout is external variable so you have to declere it in one of your source codes too).
Upvotes: 0
Reputation: 38264
What you can do is capture the std::cout.rdbuf()
with a pointer to std::streambuf
,
then i think you should be able to write all the outputs to std::cout
to some file.
Upvotes: 1
Reputation: 13431
The sync
calls can be replaced with pubsync
. As for the overflow
call I think that may be a typo. as it looks as if it should be a call to sputc
.
Upvotes: 1
Reputation: 24174
The boost::iostreams::tee_device
is made for this
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/tee.hpp>
#include <fstream>
#include <iostream>
int
main()
{
typedef boost::iostreams::tee_device<std::ostream, std::ofstream> Tee;
typedef boost::iostreams::stream<Tee> TeeStream;
std::ofstream file( "foo.out" );
Tee tee( std::cout, file );
TeeStream both( tee );
both << "this goes to both std::cout and foo.out" << std::endl;
return 0;
}
sample invocation:
samm$ ./a.out
this goes to both std::cout and foo.out
samm$ cat foo.out
this goes to both std::cout and foo.out
samm$
Upvotes: 12
Reputation: 760
if you're desperate:
#define protected public
#include <iostream>
#undef protected
this is a gross hack, but it usually works.
Upvotes: 2