开发者

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

开发者 https://www.devze.com 2023-03-03 20:29 出处:网络
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 consol开发者_如何学Ce output goes to both t

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 consol开发者_如何学Ce 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?


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$ 


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


if you're desperate:

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

this is a gross hack, but it usually works.


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.


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.


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


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

0

精彩评论

暂无评论...
验证码 换一张
取 消