Sunday, September 20, 2015

Redirection of IO stream of C++

Sometimes, for programs written in C++, at the development stage, it's probably convenient to output the diagnosis information directly to console. And upon release, by the virtue of Macro, the diagnosis information can be eliminated. However for some daemon program, probably it still needs to output something if something wrong occurs. However simply turning on the Macro might not work since the TTY has been detached from standard output terminal or stand error terminal. The following are piece of work which can direct the IO stream from terminal to files. Hope it will be helpful under some occasion.


#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

class MyLog
{
public:
    MyLog(char* path)
    {
        m_fp = fopen(path, "w");
    }
    ~MyLog()
    {        
        if (m_fp)
        {
            fclose(m_fp);
        }
    }

    void operator() (const string& s)
    {
        if (m_fp)
        {
            fprintf(m_fp, "%s\n", s.c_str());
            fflush(m_fp);
        }
    }

    void operator() (const char* fmt, ...)
    {
        if (m_fp)
        {
            char buf[256];
            va_list ap;

            memset(buf, 0, sizeof(buf));

            va_start(ap, fmt);
            buf[vsnprintf(buf, sizeof(buf), fmt, ap)] = '\0';
            va_end(ap);

            fputs(buf, m_fp);
            fflush(m_fp);
        }
    }
    
private:
    FILE* m_fp;
};

MyLog myLog("/opt/test.txt");

class Redirect
{
public:
    Redirect(MyLog& log) : m_log(log), m_oldCoutStreamBuf(cout.rdbuf())
    {
        cout.rdbuf(m_strCout.rdbuf());
    }
    ~Redirect()
    {
        m_log(m_strCout.str());
        cout.rdbuf(m_oldCoutStreamBuf);    
    }

private:
    MyLog& m_log;
    streambuf* m_oldCoutStreamBuf;
    ostringstream m_strCout;
};

void func1()
{
    Redirect r(myLog);
    cout << "in func1!" << endl;
}

void func2()
{
    Redirect r(myLog);
    cout << "in func2!" << endl;
    func1();
}

int main(int argc, char* argv[])
{
    Redirect* p = new Redirect(myLog);
    cout << "in main!" << endl;
    func2();
    delete p;
    cout << "You should see this!" << endl;
    return 0;
}

  

No comments:

Post a Comment