Suppress cout output from imported library

Hello,
I am importing a library in my code which is verbose in its standard output. I don't want to modify the imported library but I still need to keep my standard out as clean as possible. Is there a way to suppress the stdout from the imported library only, while still making my own outputs to stdout?
I don't know if the following method sets all of stdout to be in a "failure" state (a library might be using other means to print to stdout), but if the library is using default-configured cout, the following should work:
https://stackoverflow.com/questions/30184998/how-to-disable-cout-output-in-the-runtime

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
int main() {
    std::cout << "First message" << std::endl;

    std::cout.setstate(std::ios_base::failbit);
    std::cout << "Second message" << std::endl;

    std::cout.clear();
    std::cout << "Last message" << std::endl;

    return 0;
}

Outputs:

First message
Last message


So in your case, set the failbit before calling the library functions, and then clear it once it completes the call. If this is happening in some asynchronous manner, you might need to be a bit more clever.

There may be other OS-level tricks to explore if that doesn't work, but it's a good start.
For example on Linux you might be able to use dup2 to set stdout to be null?
https://man7.org/linux/man-pages/man2/dup.2.html
Last edited on
Isn't it UB to use a stream in an invalid state ?
I've never heard of such a thing, although it's hard for me to prove a negative.

30.7.5.2.1 Common requirements [ostream.formatted.reqmts]
1 Each formatted output function begins execution by constructing an object of class sentry. If this object
returns true when converted to a value of type bool, the function endeavors to generate the requested
output. If the generation fails, then the formatted output function does setstate(ios_base::failbit),
which might throw an exception. If an exception is thrown during output, then ios::badbit is turned on
in *this’s error state. If (exceptions()&badbit) != 0 then the exception is rethrown. Whether or not
an exception is thrown, the sentry object is destroyed before leaving the formatted output function. If no
exception is thrown, the result of the formatted output function is *this.

2 The descriptions of the individual formatted output functions describe how they perform output and do not
mention the sentry object.


The functions for output seems to use wording like "if possible".
basic_ostream<charT, traits>& put(char_type c);
2 Effects: Behaves as an unformatted output function (as described above). After constructing a sentry object, inserts the character c, if possible.
Last edited on
Is it possible one of the reasons why the 3rd party library is so vomitous might be for diagnostic purposes? Such as when compiling as debug? Or defining/not defining some library flag to reduce/set the amount of output?

Without knowing what the library being used makes it nigh um-possible to give an answer that isn't 100% pure unadulterated "pulled out of one's arse" ideas.
I think library code writing to std::cout or std::cerr is really bad practice. For example, many command-line programs write output to std::cout that is supposed to be pipe'd to the std::cin of the next program in the chain. A third-party library writing to std::cout unsolicited has a great potential of corrupting the output!

Anyway, you could try:
1
2
3
4
5
6
7
std::ostringstream local;
auto cout_buff = std::cout.rdbuf();
std::cout.rdbuf(local.rdbuf());

/* call library function here !!! */

std::cout.rdbuf(cout_buff);


(Note: Any "hack" that temporarily disables/redirects std::cout around library calls is not thread-safe)
Last edited on
If there is a way to suppress/reduce the volume of the output via some form of a program switch, like a #define, then writing to std::cerr isn't all that bad, if rather amateurish.

Still wouldn't be a library I'd want to use.
thmm wrote:
Isn't it UB to use a stream in an invalid state ?
No, if it were the library would be unusable.

@see17
You might take a look at the documentation of the library. Usually there is a #define to switch this output on/offf
There might also be a difference with debug/release version.
> Is there a way to suppress the stdout from the imported library only,
> while still making my own outputs to stdout?

We can create an output stream of our own which sends its output to stdout.
And then redirect the output of std::cout (which the library, presumably, uses) to a file.

For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
#include <fstream>

int main()
{
    // we use mycout to send our output to stdout
    std::ostream mycout( std::cout.rdbuf() ) ;

    // the library uses std::cout; it sends the output to a file
    std::filebuf fbuf ;
    fbuf.open( "lib_stdout.txt", std::ios::out ) ; // open a file for output
    std::cout.rdbuf( std::addressof(fbuf) ) ; // and let std::cout send its output to this file

    mycout << "our output goes to stdout\n" ;
    std::cout << "library output goes to the file 'lib_stdout.txt'\n" ;

    // once we are done, restore the original behaviour of std::cout
    std::cout.rdbuf( mycout.rdbuf() ) ;
}



If we must use the same stream std::cout both in our code and the library, things get a little more involved:

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
#include <iostream>
#include <fstream>

namespace utility
{
    struct stdout_or_file_buf : public std::basic_streambuf<char>
    {
        using streambuf_type = std::basic_streambuf<char> ;
        using traits_type = std::char_traits<char> ;
        using int_type = typename traits_type::int_type ;

        explicit stdout_or_file_buf( const std::string& file_name )
            : first( *std::cout.rdbuf() ) { second.open( file_name, std::ios::out ) ; }

        bool to_stdout() const noexcept { return out_to_first ; }
        void to_stdout( bool b ) noexcept { out_to_first = b ; }

        protected:
            virtual int_type overflow( int_type c ) override
            {
                const int_type eof = traits_type::eof() ;
                if( traits_type::eq_int_type( c, eof ) ) return traits_type::not_eof(c) ;
                else
                {
                    const auto ch = traits_type::to_char_type(c) ;
                    if(out_to_first) return traits_type::eq_int_type( first.sputc(ch), eof ) ? eof : c ;
                    else return traits_type::eq_int_type( second.sputc(ch), eof ) ? eof : c ;
                }
            }

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

        private:
            streambuf_type& first ;
            std::filebuf second ;
            bool out_to_first = true ;
    };

    struct redirector
    {
        explicit redirector( const std::string& file_name = "lib_out.txt" )
            : iobuf(file_name), old_buf( std::cout.rdbuf( std::addressof(iobuf) ) ) {}
        ~redirector() { std::cout.rdbuf(old_buf) ; }

        void cout() { iobuf.to_stdout(true) ; }
        void file() { iobuf.to_stdout(false) ; }

        // non-copyable
        redirector( const redirector& ) = delete ;
        redirector& operator= ( const redirector& ) = delete ;

        private:
            utility::stdout_or_file_buf iobuf ;
            std::streambuf* old_buf ;
    };
}

int main()
{
    utility::redirector redirirect_to("lib_out.txt") ;

    for( int i = 0 ; i < 20 ; ++i )
    {
        if( i%4 == 0 ) redirirect_to.cout() ; // my output : send to std::cout
        else redirirect_to.file() ; // output from library : send to file
        std::cout << "line #" << i << '\n' ;
    }
}
Topic archived. No new replies allowed.