2

Writing a program run in a while loop maybe for some hours, so I'm trying to redirect my cout and cerr to save log files under directory named by the date when loop started.

Problem is I have some log that should be saved before while loop, so it logs before I redirect stdout and stderr.

prepareLoop();
std::cout("Some log"); // Log before redirection
while (true)
{
   std::string date = getTodaysDate();

   // redirect stdout and stderr to log file with date on filename.
   std::ofstream logByDate { date + ".log", std::ios::app };
   std::ofstream ErrByDate { date + ".err", std::ios::app };
   std::cout.rdbuf(logByDate.rdbuf());
   std::cerr.rdbuf(ErrByDate.rdbuf());

   otherJobsToDo();
}

I thought of shell script redirecting stdout and stderr to file, like this

./myProgram.out 2>> ${date}.err 1>> ${date}.log

but it seems not working. Same output with when I execute it with no redirection on script.

Can I write those log before loop?

Summary: A program is running through days. I have to change log file when day has changed. So, I will keep redirecting stdout and stderr in loop. But there are some log outside the loop that have to be written on log. And redirecting when executing doesn't write them on log.

  • 1
    This might help with Linux: 1 is stdout and 255 is stdout, too. – Cyrus Nov 08 '19 at 05:56
  • If you do redirection when you invoke your program, no need to do it in the code, and there should be no output to the console. – dash-o Nov 08 '19 at 06:18
  • @Cyrus Yes, I'm using linux. Could you be more specific? – Jongseok Yoon Nov 08 '19 at 06:24
  • @dash-o I know, but I'm trying to redirect dynamically. Like when program runs from 23:59 to 00:01, it logs on /date/before/midnight/log.log on 23:59, then to /date/after/midnight/log.log on 00:01 – Jongseok Yoon Nov 08 '19 at 06:26
  • Can you clarify the problem. Include (partial) output if possible. 'seems not working' is confusing. – dash-o Nov 08 '19 at 06:41
  • Side note: How long does each loop iteration take? Redirecting the out/err large number of time will cause performance problem. – dash-o Nov 08 '19 at 06:43
  • @dash-o OK 'seems not working' meant cout outside the loop doesn't write log on a file. It never writes it, when I redirect it in script or not. I'm using sync_with_stdio(false) fyi, and there is sleep in loop so it takes about 2 seconds including sleep. – Jongseok Yoon Nov 08 '19 at 06:56
  • Can you try: `./myProgram.out > >(tee -a stdout.log) 2> >(tee -a stderr.log >&2)` – stephanmg Nov 08 '19 at 06:57
  • Does this answer your question? [How to redirect and append both stdout and stderr to a file with Bash?](https://stackoverflow.com/questions/876239/how-to-redirect-and-append-both-stdout-and-stderr-to-a-file-with-bash) – stephanmg Nov 08 '19 at 06:57
  • 1
    @stephanmg thanks for your help, but it wasn't the answer I find. I added the summary to clarify the problem – Jongseok Yoon Nov 08 '19 at 07:07
  • @JongseokYoon : I don't understand why you do the redirection twice: First inside the code, and then outside when invoking the program. Since you need the log to go to different files while the program is running, it certainly does not make sense to do output redirection from the outside. I would do it completely from the inside only, as you tried with `rdbuf`. – user1934428 Nov 08 '19 at 07:36
  • @JongseokYoon for the missing 'Some log', try appending "\n", it might be a buffering issue. – dash-o Nov 08 '19 at 09:01
  • 1
    For the repeat open/close. Since you will have to open the log files before the loop (to capture pre-loop output), why not add a test for date change - and reopen files then. It will give you some efficiency, and reduce 'noise' from this service. – dash-o Nov 08 '19 at 09:03

1 Answers1

1

I think it would work when I rdbuf() in program twice, but it didn't work for some reason, so I just made a class and function that writes log based on the date it is executed.

void LogWriter::writeLog(const std::string& logContent)
{
    std::string date{ getDateString() };
    std::string logDir{ logRoot + date };

    makeDirectories(logDir);  

    std::string logPath{ logDir + '/' + logName + ".log" };

    std::ofstream out{ logPath, std::ios::app };
    out << logContent;
}

It has some advantages compared to redirecting stdout and stderr, since it doesn't make empty files before it needs them.