How to redirect stderr / stdout to my C ++ log?

I use a third party, which sometimes has internal errors, when this happens, a third party writes stderr, and I see this in the console.

(I check the return values ​​of third-party functions and see that it failed, but I want the information he writes to be stderr)

I have a registrar with whom I am writing using the method that I have

SendLog(string log);

I want to somehow catch what my third-party writes to stderr (maybe listening to stderr in some way), and then write this to my journal.

How can i do this? I need this because my users do not see the console, they only see the log.

It is important to note that my program does not crash or does not exist after these errors, it continues to work.

EDIT: My question is not the same as the supposed similar question, I want to avoid using linkers (as was used in a similar question).

+4
source share
3 answers

One solution is to duplicate everything that is written in cerr, for example, a file.

This is a helper class:

class CTee {
public:
    // Use ostream &s2 if you want to duplicate to an ostream, pass other
    // stuff you need if you have other logging mechanisms.
    CTee(ostream &s1, ostream &s2) : m_s1(s1), m_s1OrigBuf(s1.rdbuf()), m_teebuf(s1.rdbuf(), s2.rdbuf()) { s1.rdbuf(&m_teebuf); }
    ~CTee() { m_s1.rdbuf(m_s1OrigBuf); }

private:
    CTee &operator =(CTee &rhs);    // not implemented

    class CTeeBuf : public streambuf {
    public:
        // Use streambuf *sb2 if you want to duplicate to an ostream/streambuf.
        // Pass other Information if you want to log to something different.
        CTeeBuf(streambuf* sb1, streambuf* sb2) :  m_sb1(sb1), m_sb2(sb2) {}

    protected:
        virtual int_type overflow(int_type c) {
            if(streambuf::traits_type::eq_int_type(c, streambuf::traits_type::eof()))
                return c;
            else {
                // Put char to cerr/stream to duplicate
                m_sb1->sputc((streambuf::char_type)c);
                // Put char to duplicate stream. If you want to duplicate to something
                // different, then write the char whereever you want to.
                return m_sb2->sputc((streambuf::char_type)c);
            }
        }
        virtual int sync() {
            m_sb1->pubsync();
            return m_sb2->pubsync();
        }

        // Store streambuf *m_sb2 if you want to duplicate to streambuf.
        // Store anything else if you want to duplicate to something different.
        streambuf *m_sb1, *m_sb2;
    };

    ostream &m_s1;
    streambuf * const m_s1OrigBuf;
    CTeeBuf m_teebuf;
};

CTee takes ostreamfor duplication and ostreamfor duplication. It takes a duplicate, which should be duplicated, and replaces it rdbuf, streambufwhich is recorded using CTeeBuf (see CTEE ctor). CTeeBuf takes charwhich are written to it and forwards them in streambufboth ostream(see CTeeBuf :: overflow and CTeeBuf :: sync). CTEE dtor returns the changed streambufto its original value.

:

char logfilename[] = "myfile.log";
ofstream logfile(logfilename, ios_base::out | ios_base::app);
CTee tee(cerr, logfile);

, cerr, logfile ( tee). , cerr, logfile:

cerr << "error occured: ..." << endl;

, . ostream, - , CTeeBuf:: overflow , , .

. http://www.cs.technion.ac.il/~imaman/programs/teestream.html http://wordaligned.org/articles/cpp-streambufs.

+2

- stringstream . ++, .

class redirect_stream
{
public:
   redirect_stream(std::ostreamstream& stream, std::ostream& oldstream) :
   stream_(stream), oldstream_(oldstream)
   {
      oldbuf_ = oldstream_.rdbuf();
      oldstream_.rdbuf(stream_.rdbuf());
   }
   ~redirect_stream()
   {
      const std::string str = stream_.str();
      if (!str.empty())
      {
         SendLog(str);
      }
      oldstream_.rdbuf(oldbuf_);
   }
private:
   std::ostringstream& stream_;
   std::ostream& olstream_;
   std::streambuf* oldbuf_;
};

:

std::ostringstream oss;
redirect_stream redirecter(oss, std::cerr);

oss.str() .

+1

You can use std :: stringstream

std::stringstream log;
std::streambuf *buf = std::cerr.rdbuf(log).rdbuf());
std::cerr << "Error Msg" << std::endl;
std::string errMsg( log.str() );

errMsg will be "Msg Error".

0
source

Source: https://habr.com/ru/post/1606592/


All Articles