9

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?

Jason Swager
  • 6,421
  • 6
  • 41
  • 56

7 Answers7

12

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$ 
Sam Miller
  • 23,808
  • 4
  • 67
  • 87
  • This works just fine for me - unfortunately, I've been asked to NOT include Boost as part of this application. Management, non-technical based decision. So - how do you do this in just std? – Jason Swager May 09 '11 at 21:25
  • @Jason it looks like there are some other answers that do not use boost. Good luck. – Sam Miller May 09 '11 at 21:50
3

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
Pang
  • 9,564
  • 146
  • 81
  • 122
Jim Thomas
  • 31
  • 1
2

if you're desperate:

#define protected public
#include <iostream>
#undef protected

this is a gross hack, but it usually works.

flownt
  • 760
  • 5
  • 11
  • At this point, I'm desperate enough to take even an ugly hack. Unfortunately, with VS2008, it doesn't help. Same original errors. – Jason Swager May 09 '11 at 21:32
1

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.

Troubadour
  • 13,334
  • 2
  • 38
  • 57
1

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.

axel22
  • 32,045
  • 9
  • 125
  • 137
A. K.
  • 34,395
  • 15
  • 52
  • 89
0

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

André Aichert
  • 313
  • 2
  • 11
0

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).

Martin Ba
  • 37,187
  • 33
  • 183
  • 337
Ali1S232
  • 3,373
  • 2
  • 27
  • 46
  • This will work for the code that we write, were we can modify our #include lines. But this won't work for the third-party code, that must also be using #include , but we can't modify due to licensing. – Jason Swager May 09 '11 at 21:27
  • then you can just modify iostream file instead! no lisence can prevent you from that! but if you have a precompiled code that's totaly a diffrent story, but you can also write a wrapper program that runs yours and do all the console works for you. though it'll take somehow much more effort! – Ali1S232 May 09 '11 at 21:43