Search code examples
c++ciofile-descriptorio-redirection

redirect stdout/stderr to file under unix c++ - again


What I want to do

redirect stdout and stderr to one or more files from inside c++

Why I need it

I am using an external, precompiled third-party library that produces a ridiculous amount of output, which I would like to redirect to a log file to keep the console clean.

Conditions

Compatibility is not a problem, the code will only run on Unix systems. The redirection should not only affect c++-style printing (std::cout << "hello world" << std::endl), but also c-style printing (printf("hello world\n")).

What I have tried so far

I have been browsing on stackoverflow for half a day, reading multiple answers to people having similar problems. With the help of these answers, I have been able to put together the following piece of code:


#include <stdio.h>
#include <iostream>
#include <fcntl.h>
#include "unistd.h"

const int stdoutfd(dup(fileno(stdout)));

int redirect_stdout(const char* fname){
  fflush(stdout);
  int newstdout = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |     S_IROTH);
  dup2(newstdout, fileno(stdout));
  close(newstdout);
}

int restore_stdout(){
  fflush(stdout);
  dup2(stdoutfd, fileno(stdout));
  close(stdoutfd);
  return stdoutfd;
}

int main(){
  redirect_stdout("/dev/null");
  std::cout << "invisible 1" << std::endl;
  restore_stdout();
  std::cout << "visible 1" << std::endl;
  redirect_stdout("/dev/null");
  std::cout << "invisible 2" << std::endl;
  restore_stdout();
  std::cout << "visible 2" << std::endl;
  return 0;
}

What I would expect to see:

visible 1
visible 2

What I actually see

visible 1

That is, when using this mechanism for the first time, it works - but if used again, restoring the output will not work. Can somebody point out to me what I need to change in order to have the mechanism work infinitely often?

EDIT: Why it is different from what everyone else is doing?

Many people have similar questions (hence the "again", e.g. here). However, here, I specifically target a solution that works for C-style and C++-style printing, and have a particular focus on the reusability of the functions - something that is generally not addressed in other questions and answers.


Solution

  • If you want to be able to reuse it, don't close stdoutfd in restore_stdout.