output to console and log file

I have 18,000 lines of code that i would like to upgrade to include a log file. I want to replace the cout with a stream or something similar so that i can easily output to the console and to a log file at the same time with minimal change to 18,000 lines of code. I'm nearly there.

I used this post heavily as a reference; http://www.cplusplus.com/forum/general/19489/ however it is highly incomplete and this is above my knowledge so I'm struggling somewhat.

I was able to get the bulk of it working with some guess work and modification to the code from that link.

For some reason i had to comment out "mstream(void);" and "~mstream(void);"

I also cannot figure out how to get
1
2
3
4
5
6
  mstream& operator<< (ostream& (*pfun)(ostream&))
  {
    pfun(coss);
    pfun(cout);
    return *this;
  }
to work for endl as per the previous link. Not sure if i'm even putting it in the right place.

Otherwise the code works fine for streamming to both locations and such. See the code below;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
#include <fstream>
#include <string>

using namespace std;

class mstream
{
  public:
  ofstream coss;
  //mstream(void);
  //~mstream(void);
};

template <class T>
mstream& operator<< (mstream& st, T val)
{
  st.coss << val;
  cout << val;
  return st;
}
/*mstream& operator<< (ostream& (*pfun)(ostream&))
{
pfun(coss);
pfun(cout);
return *this;
}*/
;

int main()
{
	mstream of;

	of.coss.open("LogFile.txt");

	if(!of.coss.is_open())
		return -1;

	string m = "the";

	of << m << 0.1  << " haha\n";

	system("pause");

	return 0;
}
> so that i can easily output to the console and to a log file at the same time
> with minimal change to 18,000 lines of code
none
$ a.out | tee log_file
Thanks ne555, I looked into that but it's not a feasible solution for my application.

I would like to finish the nearly complete solution above. Is anyone else able to help?
We'll I'm pretty bummed that no one was able to help out but I came up with a solution through persistence. The problem is i have no idea if it's healthy code or not. Anyways i wanted to post the solution so the next guy looking can figure it out.

I took a piece from here as well; http://stackoverflow.com/questions/1134388/stdendl-is-of-unknown-type-when-overloading-operator

Using the method below you can simply replace all of your cout << with sout << which is what i was going for. Just make sure you don't replace the cout inside of the soutstream template like i did. Good Luck!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <fstream>
#include <string>
#include <ctime>
#include <stdio.h>

using namespace std;

class soutstream
{
  public:
  ofstream coss;

  // this is the type of std::cout
	typedef std::basic_ostream<char, std::char_traits<char> > CoutType;

	// this is the function signature of std::endl
	typedef CoutType& (*StandardEndLine)(CoutType&);

	// define an operator<< to take in std::endl
	soutstream& operator<<(StandardEndLine manip)
	{
		// call the function, but we cannot return it's value
		manip(std::cout);

		coss << "\n";


		return *this;
	}
};

template <class T>
soutstream& operator<< (soutstream& st, T val)
{
  st.coss << val;
  cout << val;
  return st;
}

string GetDateTime();

soutstream sout;

int main()
{

	sout.coss.open("LogFile_" + GetDateTime() + ".txt");

	if(!sout.coss.is_open())
		return -1;

	string m = "the ";

	sout << m << 0.1  << " haha\n\n";

	sout << "1\n\n2\n3";

	sout << "bla1" << endl << "ble2" << endl << endl << endl << endl;

	system("pause");

	system("cls");

	sout << "\nthe word\n the";

        system("pause");

	sout.coss.close();

	return 0;
}

string GetDateTime()
{
	time_t t = time(0);   // get time now
        struct tm * now = localtime( & t );

	int yearval=(now->tm_year + 1900);
	int monthval=(now->tm_mon + 1);
	int dayval=(now->tm_mday);
	int hourval=(now->tm_hour);
	int minval=(now->tm_min);
	int secval=(now->tm_sec);
	
	char c_year[12];
	sprintf_s(c_year, "%d", yearval);
	char c_month[12];
	sprintf_s(c_month, "%d", monthval);
	char c_day[12];
	sprintf_s(c_day, "%d", dayval);
	char c_hour[12];
	sprintf_s(c_hour, "%d", hourval);
	char c_min[12];
	sprintf_s(c_min, "%d", minval);
	char c_sec[12];
	sprintf_s(c_sec, "%d", secval);

	string output = "";

	output += c_year;
	output += "-";
	output += c_month;
	output += "-";
	output += c_day;
	output += "_";
	output += c_hour;
	output += "-";
	output += c_min;
	output += "-";
	output += c_sec;


	return output;

}
> I have 18,000 lines of code that i would like to upgrade to include a log file.
> I want to replace the cout with a stream or something similar
> so that i can easily output to the console and to a log file at the same time
> with minimal change to 18,000 lines of code.

Don't take chances with 18,000 lines of code; just use boost::iostreams::tee_device
http://www.boost.org/doc/libs/1_53_0/libs/iostreams/doc/index.html

If you want get an idea of how a tee could be implemented:
http://www.cplusplus.com/forum/general/64174/#msg347154
Don't take chances with 18,000 lines of code; just use boost::iostreams::tee_device
http://www.boost.org/doc/libs/1_53_0/libs/iostreams/doc/index.html


Thanks for the feedback. I did just that. I took the leap and download/installed and set up boost for the first time ever.

Here's what I came up with.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <boost/iostreams/tee.hpp>
#include <boost/iostreams/stream.hpp>
#include <fstream>
#include <iostream>

using namespace std;

namespace bio = boost::iostreams;
using bio::tee_device;
using bio::stream;

typedef tee_device<ostream, ofstream> TeeDevice;
typedef stream<TeeDevice> TeeStream;

ofstream ofs("sample.txt");
TeeDevice my_tee(cout, ofs); 
TeeStream my_split(my_tee);

int main()
{
	if(!ofs.is_open())
		return -1;

    my_split << "Line1\n";
    my_split << "Line2" << endl;
	int var1 = -123;
    my_split << "var1= " << var1 << " Line3\n";
    my_split << 0.23 << " Line4" << endl << endl << endl;

    system("pause");

    my_split.flush();
    my_split.close();
}
Argghh, so close! This boost method will not output to console until it encounters an endl or flush (endl calls flush). And I'm going to reiterate for those who choose not to read the previous posts, i don't want to sift through 18,000 lines of code and add flush where necessary. Thoughts? For now I guess I can go back to the other method but it doesn't include all of the stream operators so will be problematic in the future.
> This boost method will not output to console until it encounters an endl or flush

Which is the behaviour of std::cout

By default, std::cin is tied to std::cout; so std::cout is flushed before an operation on std::cin.

Tie the teestream to std::cin to get the same behaviour.
std::cin.tie( &my_split ) ; // add this right at the beginning


> For now I guess I can go back to the other method but it doesn't include
> all of the stream operators so will be problematic in the future.

This one does support all stream operations
http://www.cplusplus.com/forum/general/64174/#msg347154


Using cin.tie didn't seem to resolve the issue but i ended up implementing the code in your other link. It seems to work well but I haven't gotten to test it rigorously. Thanks for all the help!!!!
> i ended up implementing the code in your other link.

With the code in that link, you can even do this:

a. In main(), right at the beginning, create a teebuf.
b. Set the streambuf to be used by std::cout to the teebuf
c. The rest of the program continues to use std::cout as before; even sync_with_stdio() works as expected.
d. At the end, before returning from main(), flush std::cout and reset its streambuf back to the original.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>

template < typename C, typename T = std::char_traits<C> >
struct basic_teebuf : public std::basic_streambuf<C,T>
{
    typedef std::basic_streambuf<C,T> streambuf_type ;
    typedef typename T::int_type int_type ;

    basic_teebuf( streambuf_type* buff_a, streambuf_type* buff_b )
            : first(buff_a), second(buff_b) {}

    protected:
        virtual int_type overflow( int_type c )
        {
            const int_type eof = T::eof() ;
            if( T::eq_int_type( c, eof ) ) return T::not_eof(c) ;
            else
            {
                const C ch = T::to_char_type(c) ;
                if( T::eq_int_type( first->sputc(ch), eof ) ||
                    T::eq_int_type( second->sputc(ch), eof ) )
                        return eof ;
                else return c ;
            }
        }

        virtual int sync()
        { return !first->pubsync() && !second->pubsync() ? 0 : -1 ; }

    private:
        streambuf_type* first ;
        streambuf_type* second ;
};

template < typename C, typename T = std::char_traits<C> >
struct basic_teestream : public std::basic_ostream<C,T>
{
    typedef std::basic_ostream<C,T> stream_type ;
    typedef basic_teebuf<C,T> streambuff_type ;

    basic_teestream( stream_type& first, stream_type& second )
         : stream_type(&stmbuf), stmbuf( first.rdbuf(), second.rdbuf() ) {}

    basic_teestream( streambuff_type* first, streambuff_type* second )
         : stream_type(&stmbuf), stmbuf(first,second ) {}

    ~basic_teestream() { stmbuf.pubsync() ; }

    private: streambuff_type stmbuf ;
};

typedef basic_teebuf<char> teebuf ;
typedef basic_teestream<char> teestream ;

#include <fstream>
#include <iomanip>
#include <algorithm>
#include <iterator>

int main()
{
    std::filebuf fbuf ;
    fbuf.open( "out.txt", std::ios::out ) ;
    std::streambuf* stdoutbuf = std::cout.rdbuf() ;
    teebuf tbuf( &fbuf, stdoutbuf ) ;
    std::cout.rdbuf( &tbuf ) ;

    std::cout << std::boolalpha << ('A'==65) << ' ' << "hello world!" << std::fixed
               << std::setprecision(3) << std::setw(12) << std::setfill('*') << 12.4538 << '\n' ;

    int a[] = { 10, 20, 30, 40, 50, 60 } ;
    std::copy( a, a+6, std::ostream_iterator<int>( std::cout, " " ) ) ;

    std::cout << std::endl ;
    std::cout.rdbuf( stdoutbuf ) ;
}
Topic archived. No new replies allowed.