Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. How to redirect stdout & stderr to a file in a Qt console App (QCoreApplication) ?
QtWS25 Last Chance

How to redirect stdout & stderr to a file in a Qt console App (QCoreApplication) ?

Scheduled Pinned Locked Moved Solved General and Desktop
stdoutredirectconsole app
19 Posts 6 Posters 12.2k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    eupuser00
    wrote on 14 Feb 2020, 15:30 last edited by
    #1

    Hello.

    I am running a Qt console app in Windows with a detached console. The app has a server to handle some requests and also to act upon some file-watchers. Internally I call some external executables which print messages to stdout.

    I want all the output messages of the app (and executables called internally) to be logged in a file instead of stdout. I have used "qInstallMessageHandler" to capture the logs. But this only logs the messages logged through "qDebug()" and the other messages which are directed to stdout are left out.

    I tired using "freopen" and it didn't redirect the stdout to the specified file even though I got proper return ptr value from the call.

    Is it possible to redirect all output to stdout and stderr to a file when running an console app using QCoreApplication?

    Thank you in advance.

    J 1 Reply Last reply 14 Feb 2020, 15:41
    1
    • C Online
      C Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on 14 Feb 2020, 15:35 last edited by
      #2

      @eupuser00 said in How to redirect stdout & stderr to a file in a Qt console App (QCoreApplication) ?:

      Internally I call some external executables which print messages to stdout.

      See QProcess::readAllStandardOutput() and it's corresponding signals.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      0
      • E eupuser00
        14 Feb 2020, 15:30

        Hello.

        I am running a Qt console app in Windows with a detached console. The app has a server to handle some requests and also to act upon some file-watchers. Internally I call some external executables which print messages to stdout.

        I want all the output messages of the app (and executables called internally) to be logged in a file instead of stdout. I have used "qInstallMessageHandler" to capture the logs. But this only logs the messages logged through "qDebug()" and the other messages which are directed to stdout are left out.

        I tired using "freopen" and it didn't redirect the stdout to the specified file even though I got proper return ptr value from the call.

        Is it possible to redirect all output to stdout and stderr to a file when running an console app using QCoreApplication?

        Thank you in advance.

        J Offline
        J Offline
        JonB
        wrote on 14 Feb 2020, 15:41 last edited by JonB
        #3

        @eupuser00
        You can do as @Christian-Ehrlicher has just posted, but that will only affect stdout writing from child processes. I believe you are asking for redirection of anything written within your calling program itself, libraries etc.

        I'm not a C++-er, but I think your current problem is: stuff written to C++ cout is not the same thing as stuff written to stdout? See http://www.cplusplus.com/reference/iostream/cout/ and http://www.cplusplus.com/reference/ios/ios_base/sync_with_stdio/

        If the streams are synchronized, a program can mix iostream operations with stdio operations, and their observable effects are guaranteed to follow the same order as used in the thread.

        I don't know what the "synchronized" & "observable effects" add up to, but it may be that cout uses file handle #1 like stdout does but it does not actually use stdout --- so freopen() won't be enough.

        You either ought do your redirection on low-level file handles 0/1/2 (fdopen(), and possibly some dup()-ping, IIRC) instead of just on stdin/out/err, or perhaps cout has its own thing. Googling for something about "redirecting stdout cout" might help you.

        1 Reply Last reply
        0
        • E Offline
          E Offline
          eupuser00
          wrote on 14 Feb 2020, 15:52 last edited by
          #4

          @Christian-Ehrlicher

          Thanks. But your suggestion works when I am using QProcess to execute the external binaries. And as @JonB says I need to redirect everything from my main program.

          1 Reply Last reply
          0
          • C Online
            C Online
            Christian Ehrlicher
            Lifetime Qt Champion
            wrote on 14 Feb 2020, 15:57 last edited by
            #5

            @eupuser00 said in How to redirect stdout & stderr to a file in a Qt console App (QCoreApplication) ?:

            I need to redirect everything from my main program.

            Why do you use cout in your own program in the first place? Esp. when it has no console...

            Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
            Visit the Qt Academy at https://academy.qt.io/catalog

            1 Reply Last reply
            0
            • E Offline
              E Offline
              eupuser00
              wrote on 14 Feb 2020, 16:05 last edited by
              #6

              No, I am not using cout at all (only qDebug, qWarning,...). But the external tools or the libs use it and they log to stdout and these messages are only visible in Qt app output console(if i run the tool from Qt Creator) and not in my redirected log files.

              1 Reply Last reply
              0
              • H Online
                H Online
                hskoglund
                wrote on 14 Feb 2020, 16:10 last edited by
                #7

                Hi, what happens if you launch your console app with an ancient "DOS"-style redirection, e.g.

                yourconsoleapp.exe > filename.txt
                
                E 1 Reply Last reply 14 Feb 2020, 16:17
                2
                • H hskoglund
                  14 Feb 2020, 16:10

                  Hi, what happens if you launch your console app with an ancient "DOS"-style redirection, e.g.

                  yourconsoleapp.exe > filename.txt
                  
                  E Offline
                  E Offline
                  eupuser00
                  wrote on 14 Feb 2020, 16:17 last edited by
                  #8

                  @hskoglund

                  Not output at all. freopen is not logging anything when i use:
                  freopen("log_file.txt", "w", stdout);
                  or
                  freopen("log_file.txt", "w", (FILE*)1);

                  Also Qt keeps complaining for freopen :

                  main.cpp:16:1: warning: 'freopen' is deprecated: This function or variable may be unsafe. Consider using freopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
                  stdio.h:242:20: note: 'freopen' has been explicitly marked deprecated here
                  vcruntime.h:255:55: note: expanded from macro '_CRT_INSECURE_DEPRECATE'
                  vcruntime.h:245:47: note: expanded from macro '_CRT_DEPRECATE_TEXT'

                  J 1 Reply Last reply 14 Feb 2020, 16:33
                  0
                  • H Online
                    H Online
                    hskoglund
                    wrote on 14 Feb 2020, 16:18 last edited by
                    #9

                    Same if you omit all freopen() calls?

                    1 Reply Last reply
                    0
                    • E eupuser00
                      14 Feb 2020, 16:17

                      @hskoglund

                      Not output at all. freopen is not logging anything when i use:
                      freopen("log_file.txt", "w", stdout);
                      or
                      freopen("log_file.txt", "w", (FILE*)1);

                      Also Qt keeps complaining for freopen :

                      main.cpp:16:1: warning: 'freopen' is deprecated: This function or variable may be unsafe. Consider using freopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
                      stdio.h:242:20: note: 'freopen' has been explicitly marked deprecated here
                      vcruntime.h:255:55: note: expanded from macro '_CRT_INSECURE_DEPRECATE'
                      vcruntime.h:245:47: note: expanded from macro '_CRT_DEPRECATE_TEXT'

                      J Offline
                      J Offline
                      JonB
                      wrote on 14 Feb 2020, 16:33 last edited by
                      #10

                      @eupuser00
                      Is there any reason you don't want to look at low-level e.g. fdopen() when I've already explained that you need to do that to achieve what you want, and why stdout does not work for you? Makes me wonder what the point of answering was.

                      E 1 Reply Last reply 17 Feb 2020, 19:28
                      0
                      • C Online
                        C Online
                        Christian Ehrlicher
                        Lifetime Qt Champion
                        wrote on 14 Feb 2020, 16:52 last edited by
                        #11

                        @eupuser00 said in How to redirect stdout & stderr to a file in a Qt console App (QCoreApplication) ?:

                        But the external tools or the libs use it and they log to stdout and these messages

                        So how do you call them when not with QProcess? And when you use something else - why not use QProcess?

                        Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                        Visit the Qt Academy at https://academy.qt.io/catalog

                        1 Reply Last reply
                        1
                        • J JonB
                          14 Feb 2020, 16:33

                          @eupuser00
                          Is there any reason you don't want to look at low-level e.g. fdopen() when I've already explained that you need to do that to achieve what you want, and why stdout does not work for you? Makes me wonder what the point of answering was.

                          E Offline
                          E Offline
                          eupuser00
                          wrote on 17 Feb 2020, 19:28 last edited by
                          #12

                          @hskoglund
                          Command line style redirection didn't work when I used "2>&1 > file" as one of the arguments to the QProcess::start().
                          With "freopen()" even the qDebug messages which were logged through my custom msg handler was failing. (Without "freopen()" the qDebug messages were logged.)

                          @Christian-Ehrlicher
                          I was calling the external programs through the static function in "QProcess::execute()". But now switched to use the "QProcess::start()" so that I can use "QProcess::setProcessChannelMode()" as shown below.

                          @JonB
                          I was able to get it working with File Handles and dup(). Here is the code snippet:

                          // Global scope
                          // Setting same file for stdout & stderr (and qDebug from custom msg handler 
                          // func, "customMessageOutput")
                          QFile outFile("log_file.txt");
                          
                          execProg(){
                            ...
                            QProcess extTool;
                            extTool.setProcessChannelMode(QProcess::ForwardedChannels);
                            extTool.start(program, arg);
                            extTool.waitForFinished();
                            ...
                          }  
                          
                          redirect_stdout_stderr() {
                             outFile.open(QIODevice::WriteOnly | QIODevice::Append)
                            fout = outFile.handle();
                           
                            // redirect stdout 
                            _dup2(fout, _fileno(stdout))
                          
                            // redirect stderr 
                            _dup2(_fileno(stdout), _fileno(stderr))
                          }
                          
                          main(){
                            redirect_stdout_stderr();    
                            // Installing a custom message handler
                            // Note: Definition for "customMessageOutput" is not shown here.
                            qInstallMessageHandler(customMessageOutput);
                            ...
                            execProg();
                            ...
                          }
                          
                          • For brevity, I have not included error handling.

                          • I had trouble to redirect both stdout and stderr to the same file. I was opening the same file twice and trying to use 2 file descriptors/ handles. This got solved when I used:
                            _dup2(_fileno(stdout), _fileno(stderr))

                          Thank you all for the suggestions and pointing me towards the right direction to achieve a solution.

                          I would like to know whether there is a better/elegant solution in Qt? If yes, then I would like to adapt to it.

                          PS: I will mark this thread as "solved" once I get some or no suggestions.

                          J D 2 Replies Last reply 17 Feb 2020, 19:40
                          1
                          • E eupuser00
                            17 Feb 2020, 19:28

                            @hskoglund
                            Command line style redirection didn't work when I used "2>&1 > file" as one of the arguments to the QProcess::start().
                            With "freopen()" even the qDebug messages which were logged through my custom msg handler was failing. (Without "freopen()" the qDebug messages were logged.)

                            @Christian-Ehrlicher
                            I was calling the external programs through the static function in "QProcess::execute()". But now switched to use the "QProcess::start()" so that I can use "QProcess::setProcessChannelMode()" as shown below.

                            @JonB
                            I was able to get it working with File Handles and dup(). Here is the code snippet:

                            // Global scope
                            // Setting same file for stdout & stderr (and qDebug from custom msg handler 
                            // func, "customMessageOutput")
                            QFile outFile("log_file.txt");
                            
                            execProg(){
                              ...
                              QProcess extTool;
                              extTool.setProcessChannelMode(QProcess::ForwardedChannels);
                              extTool.start(program, arg);
                              extTool.waitForFinished();
                              ...
                            }  
                            
                            redirect_stdout_stderr() {
                               outFile.open(QIODevice::WriteOnly | QIODevice::Append)
                              fout = outFile.handle();
                             
                              // redirect stdout 
                              _dup2(fout, _fileno(stdout))
                            
                              // redirect stderr 
                              _dup2(_fileno(stdout), _fileno(stderr))
                            }
                            
                            main(){
                              redirect_stdout_stderr();    
                              // Installing a custom message handler
                              // Note: Definition for "customMessageOutput" is not shown here.
                              qInstallMessageHandler(customMessageOutput);
                              ...
                              execProg();
                              ...
                            }
                            
                            • For brevity, I have not included error handling.

                            • I had trouble to redirect both stdout and stderr to the same file. I was opening the same file twice and trying to use 2 file descriptors/ handles. This got solved when I used:
                              _dup2(_fileno(stdout), _fileno(stderr))

                            Thank you all for the suggestions and pointing me towards the right direction to achieve a solution.

                            I would like to know whether there is a better/elegant solution in Qt? If yes, then I would like to adapt to it.

                            PS: I will mark this thread as "solved" once I get some or no suggestions.

                            J Offline
                            J Offline
                            JonB
                            wrote on 17 Feb 2020, 19:40 last edited by
                            #13

                            @eupuser00
                            Well done! For heeding the advice, and for getting the code right :)

                            Yes, dup/dup2 is for merging stdout & stderr.

                            From a GUI I did something like the following during start up in old code

                            close(0);
                            close(1);
                            close(2);
                            open("/dev/null", O_RDONLY);
                            open(logfile, O_WRONLY);
                            dup(1);
                            

                            I like having stdin (0) opened from a null device, so any attempt to read from it delivers EOF.

                            Qt isn't going to provide a better solution. This operates at the lowest level.

                            You might have to check your code on Windows. Hopefully it works, I suspect I did that stuff via native calls as their will be some situation where it's better.

                            1 Reply Last reply
                            0
                            • D Offline
                              D Offline
                              David K. Hess
                              wrote on 7 Oct 2021, 23:45 last edited by
                              #14

                              Late to the party, but figured out some more of this situation that may help others.

                              The straight duping to fd 1 or 2 and/or use of _fileno() with stdout and stderr don't work when the app is launched normally within Windows by say a double-click in File Explorer (and thus has no console). The reason why is in that situation stdout and stderr both have an fd of -2 which I suppose indicates they are open for purposes of not breaking calling code but are not open in terms of actually doing anything when used. In other words, sort of a CRT /dev/null setup.

                              More info on that situation here: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fileno?view=msvc-160

                              So, this general pattern worked for me:

                                      FILE *loggingStreamStdout;
                                      FILE *loggingStreamStderr;
                                      QFile loggingFile("app.log");
                              
                                      loggingFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered);
                                      int fd = loggingFile.handle();
                              
                                      freopen_s(&loggingStreamStdout, "\\\\.\\NUL", "w", stdout);
                                      setvbuf(loggingStreamStdout, NULL, _IONBF, 0);
                                      freopen_s(&loggingStreamStderr, "\\\\.\\NUL", "w", stderr);
                                      setvbuf(loggingStreamStderr, NULL, _IONBF, 0);
                                      _dup2(fd, _fileno(stdout));
                                      _dup2(fd, _fileno(stderr));
                              
                                      qInstallMessageHandler(messageOutput);
                              

                              That uses a QFile to handle your log file and then freopens stdout and stderr on Window's version of /dev/null. This gives them valid file descriptors (instead of the -2). Then you can _dup2() the log file fd to them. I also like to set the streams as non-buffered so that tools like Baretail.exe show real-time output from the exe.

                              D 1 Reply Last reply 21 Nov 2022, 15:58
                              1
                              • D David K. Hess
                                7 Oct 2021, 23:45

                                Late to the party, but figured out some more of this situation that may help others.

                                The straight duping to fd 1 or 2 and/or use of _fileno() with stdout and stderr don't work when the app is launched normally within Windows by say a double-click in File Explorer (and thus has no console). The reason why is in that situation stdout and stderr both have an fd of -2 which I suppose indicates they are open for purposes of not breaking calling code but are not open in terms of actually doing anything when used. In other words, sort of a CRT /dev/null setup.

                                More info on that situation here: https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/fileno?view=msvc-160

                                So, this general pattern worked for me:

                                        FILE *loggingStreamStdout;
                                        FILE *loggingStreamStderr;
                                        QFile loggingFile("app.log");
                                
                                        loggingFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Unbuffered);
                                        int fd = loggingFile.handle();
                                
                                        freopen_s(&loggingStreamStdout, "\\\\.\\NUL", "w", stdout);
                                        setvbuf(loggingStreamStdout, NULL, _IONBF, 0);
                                        freopen_s(&loggingStreamStderr, "\\\\.\\NUL", "w", stderr);
                                        setvbuf(loggingStreamStderr, NULL, _IONBF, 0);
                                        _dup2(fd, _fileno(stdout));
                                        _dup2(fd, _fileno(stderr));
                                
                                        qInstallMessageHandler(messageOutput);
                                

                                That uses a QFile to handle your log file and then freopens stdout and stderr on Window's version of /dev/null. This gives them valid file descriptors (instead of the -2). Then you can _dup2() the log file fd to them. I also like to set the streams as non-buffered so that tools like Baretail.exe show real-time output from the exe.

                                D Offline
                                D Offline
                                Developer123
                                wrote on 21 Nov 2022, 15:58 last edited by
                                #15

                                @David-K-Hess It says identifier "_dup2" is undefined

                                1 Reply Last reply
                                0
                                • E eupuser00
                                  17 Feb 2020, 19:28

                                  @hskoglund
                                  Command line style redirection didn't work when I used "2>&1 > file" as one of the arguments to the QProcess::start().
                                  With "freopen()" even the qDebug messages which were logged through my custom msg handler was failing. (Without "freopen()" the qDebug messages were logged.)

                                  @Christian-Ehrlicher
                                  I was calling the external programs through the static function in "QProcess::execute()". But now switched to use the "QProcess::start()" so that I can use "QProcess::setProcessChannelMode()" as shown below.

                                  @JonB
                                  I was able to get it working with File Handles and dup(). Here is the code snippet:

                                  // Global scope
                                  // Setting same file for stdout & stderr (and qDebug from custom msg handler 
                                  // func, "customMessageOutput")
                                  QFile outFile("log_file.txt");
                                  
                                  execProg(){
                                    ...
                                    QProcess extTool;
                                    extTool.setProcessChannelMode(QProcess::ForwardedChannels);
                                    extTool.start(program, arg);
                                    extTool.waitForFinished();
                                    ...
                                  }  
                                  
                                  redirect_stdout_stderr() {
                                     outFile.open(QIODevice::WriteOnly | QIODevice::Append)
                                    fout = outFile.handle();
                                   
                                    // redirect stdout 
                                    _dup2(fout, _fileno(stdout))
                                  
                                    // redirect stderr 
                                    _dup2(_fileno(stdout), _fileno(stderr))
                                  }
                                  
                                  main(){
                                    redirect_stdout_stderr();    
                                    // Installing a custom message handler
                                    // Note: Definition for "customMessageOutput" is not shown here.
                                    qInstallMessageHandler(customMessageOutput);
                                    ...
                                    execProg();
                                    ...
                                  }
                                  
                                  • For brevity, I have not included error handling.

                                  • I had trouble to redirect both stdout and stderr to the same file. I was opening the same file twice and trying to use 2 file descriptors/ handles. This got solved when I used:
                                    _dup2(_fileno(stdout), _fileno(stderr))

                                  Thank you all for the suggestions and pointing me towards the right direction to achieve a solution.

                                  I would like to know whether there is a better/elegant solution in Qt? If yes, then I would like to adapt to it.

                                  PS: I will mark this thread as "solved" once I get some or no suggestions.

                                  D Offline
                                  D Offline
                                  Developer123
                                  wrote on 21 Nov 2022, 16:03 last edited by
                                  #16

                                  @eupuser00 it's almost useless for other people if you paste incomplete code...

                                  C D 2 Replies Last reply 21 Nov 2022, 16:08
                                  0
                                  • D Developer123
                                    21 Nov 2022, 16:03

                                    @eupuser00 it's almost useless for other people if you paste incomplete code...

                                    C Online
                                    C Online
                                    Christian Ehrlicher
                                    Lifetime Qt Champion
                                    wrote on 21 Nov 2022, 16:08 last edited by
                                    #17

                                    @Developer123 said in How to redirect stdout & stderr to a file in a Qt console App (QCoreApplication) ?:

                                    it's almost useless for other people if you paste incomplete code...

                                    _dup2() is a function, a function is defined in a header (as all functions not defined in the same source). Since the op did not post the includes you have to search the correct one by yourself which shouldn't be too hard. First google link: https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/dup-dup2?view=msvc-170

                                    Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
                                    Visit the Qt Academy at https://academy.qt.io/catalog

                                    1 Reply Last reply
                                    1
                                    • D Developer123
                                      21 Nov 2022, 16:03

                                      @eupuser00 it's almost useless for other people if you paste incomplete code...

                                      D Offline
                                      D Offline
                                      Developer123
                                      wrote on 22 Nov 2022, 11:48 last edited by
                                      #18

                                      @Developer123 I found a solution to print everything to a file, if anyone else needs, works out of the box

                                      https://stackoverflow.com/a/11202102/2076973

                                      J 1 Reply Last reply 22 Nov 2022, 11:50
                                      0
                                      • D Developer123
                                        22 Nov 2022, 11:48

                                        @Developer123 I found a solution to print everything to a file, if anyone else needs, works out of the box

                                        https://stackoverflow.com/a/11202102/2076973

                                        J Offline
                                        J Offline
                                        JonB
                                        wrote on 22 Nov 2022, 11:50 last edited by
                                        #19

                                        @Developer123
                                        The code answers there all implement sending Qt error messages within an application to a file. Perfectly useful in itself, but nothing to do with the topic title here of "How to redirect stdout & stderr to a file in a Qt console App (QCoreApplication)".

                                        1 Reply Last reply
                                        0

                                        • Login

                                        • Login or register to search.
                                        • First post
                                          Last post
                                        0
                                        • Categories
                                        • Recent
                                        • Tags
                                        • Popular
                                        • Users
                                        • Groups
                                        • Search
                                        • Get Qt Extensions
                                        • Unsolved