Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom C++ cout class - output to both console and log file

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?

like image 883
Jason Swager Avatar asked May 09 '11 20:05

Jason Swager


2 Answers

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$ 
like image 140
Sam Miller Avatar answered Sep 24 '22 05:09

Sam Miller


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
like image 45
Jim Thomas Avatar answered Sep 26 '22 05:09

Jim Thomas