Output to two streams

I was wondering if there was a way I could have a stream for logging output to stdout and a file.

The idea would be that I could just do this:
log << "Event occurred\n";
and it would write it to two streams (std::cerr and a file).

I don't see how that could be done, though; so I was thinking I'd have to use a function, like
log("%s\n", "Event occurred");

You can make your own trick class and overload <<
Thanks Bazzy. I'll try something like that.
Last edited on
what are the odds of that I was just pondering this same idea not even an hour ago.
I don't know what to use as the type of the return value and the parameter. I thought about using a template; but then won't I have to do something like log <std::string><< "Hello!";?

So what do I replace <type> with here?
1
2
3
4
5
<type> operator<<(<type> out)
{
    std::cerr << out;
    logfile << out;
}


It works with polymorphism but I can't do log << "Hello" << ", world!";; I would have to do log << "Hello, world!"; instead, whereas with std::cerr you can do the former. How can I do this?

@Seraphimsan,
Wow, really? What are you writing? I need a logging function for my emulator so that later on people will be able to tell exactly what caused that damn triple fault.
Last edited on
You might have to do some magic to make stream manipulators work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class dual_stream {
public:
    dual_stream(std::ostream& os1, std::ostream& os2) : os1(os1), os2(os2) {}

    template<class T>
    dual_stream& operator<<(const T& x) {
        os1 << x;
        os2 << x;
        return *this;
    }
private:
    std::ostream& os1;
    std::ostream& os2;
};
Last edited on
@R0mai,
Thanks for that, but why do you return a reference to class dual_stream?
So you can chain operator<< calls, just like for std::ostream :

1
2
dual_stream ds(/*two streams*/);
ds << "xyz " << 4 << " " << 3.14 << '\n';
Oh, I see... thank you :)
Nice *takes note of all this* and chrisname I'm writing a video game. But I'm likely going to put that in a header in my includes folder for MinGW...cause I often have use of an error reporting system.
Like I said, I'm using it for my emulator, e.g.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
    /* Load the BIOS into (real) memory */
    std::ifstream BIOS;
    BIOS.open(biosfile);
    
    if (BIOS.is_open()) {
        std::string line;

        log << em64::timestamp() << "Found BIOS file \"" << biosfile << "\"\n";
        
        while (!BIOS.eof()) {
            std::getline(std::cin, line);
            buffer += line;
        }
    
        BIOS.close();
    } else {
        log << em64::timestamp() << "Couldn't find/open file \"" << biosfile
            << "\"; check the file exists in the current directory and that you"
            << "have permission to read it.\n";

        return 1;        
    }
    
    log << em64::timestamp() << "Loaded BIOS into memory; running...\n";


This is what the class looks like
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
    class outlog {
        private:
            std::ofstream logfile;
        public:
            outlog(const char* file)
            {
                logfile.open(file);
        
                if (!(logfile.is_open())) {
                    std::cerr << "[]: Couldn't open file \"" << file << "\" for logging.\n";
                    this->~outlog(); /* Destroy the object */
                }
            }

            ~outlog()
            {
                if (logfile.is_open())
                    logfile.close();
            }

            template <class T>
            outlog& operator<<(const T& out)
            {
                std::cerr << out;
                logfile << out;

                return *this;
            }
    };
Last edited on
Boost tee.
http://www.boost.org/doc/libs/1_42_0/libs/iostreams/doc/functions/tee.html

You could write your own if you want, but it is a bit of a pain [to get it right]...
Last edited on
Well, the method above works very well for me. I'm not sure of the performance hit of calling operator<< 3 times on everything (ofstream and ostream's operator<< overloads are called too) but R0mai's method is easy to understand and extensible. Thanks for the suggestion, but I think I'm going to stick to the above. If I needed (for whatever reason) more than one logfile, it would be very easy to add one...

Thanks anyway, Duoas.

Edit: Boost isn't standard yet, anyway, is it? A design goal of the program is to have as few unreasonable* dependencies as possible (at the moment, three (SeaBIOS, VGABIOS and SDL)); and I won't add anything to the list unless I have to. As the class in place already does everything I need, I don't see it as being necessary to add Boost to my list of dependencies.

*an "unreasonable dependancy" being one that you couldn't reasonably expect someone wanting to compile your program to have.
Last edited on
I would say boost is almost standard. A lot of stuff from boost is getting implemented in C++0x.
Topic archived. No new replies allowed.