Boost::log stdout is displayed only after execution when called from bash script

Issue

I’m running a php file on a webserver, which executes a bash script. The stdout of the script should be streamed to a file, such that the client can fetch and display it.

The script myscript.sh:

#!/bin/bash
echo "-- starting --"
EXE="/home/username/mybinary"
ARGS="/home/username/config.cfg"
PRE="sudo"
$PRE $EXE $ARGS
echo "-- finished --"

The calling php:

$fplog = fopen("../bin/log.txt", "w");
if( ($fp = popen("sudo /home/username/src/myscript.sh", "r")) ) {
    while( !feof($fp) ){
        $logline = fgets($fp);
        fwrite($fplog, $logline);
        fflush($fplog);
    }
    fclose($fp);
} else {
    /* error handling */;
}

Why is the output not streamed to log.txt during execution?

When I run sudo ./myscript.sh in the terminal, the output of mybinary is printed as expected while it’s running. However, when I call myscript via php, all I get is -- starting --. The rest of the output will only be put out when mybinary has finished.

I’ve also tried redirecting stdout inside myscript with &> or &> | tee to the log file which yields the same results.

How can I get to the stdout of mybinary in this setup?

EDIT: Seems like boost::log was not flushing when not running in a terminal. I edited the post and title accordingly.

Solution

mybinary was using boost::log::trivial which – as I just learned – seems not to flush its output when it’s not running in a terminal.

My solution was to write the output directly from within mybinary.

If anyone’s also struggeling with boost logging, here’s my solution:

#include <boost/log/core.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/utility/setup/file.hpp> //necessary for boost::log::add_file_log
#include <boost/log/utility/setup/common_attributes.hpp> //necessary for formating options (%TimeStamp%, ...)
#include <string>

void initLog(std::string &logFilePath) {
    boost::log::add_common_attributes(); //init %TimeStamp%, etc
    if (!logFilePath.empty()) {
        boost::log::add_file_log(
            boost::log::keywords::file_name = logFilePath.c_str(),
            boost::log::keywords::auto_flush = true, /* flush after each call */
            boost::log::keywords::format = "[%TimeStamp%] [%Severity%]: %Message%"
        );
    }
#ifndef NDEBUG
   boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::debug);
#else
   boost::log::core::get()->set_filter(boost::log::trivial::severity >= boost::log::trivial::info);
#endif
}

int main() {
    std::string logFilePath;
    if (argc > 1) {
       logFilePath = argv[1];
    }

    initLog(logFilePath);

    BOOST_LOG_TRIVIAL(info) << "Running mybinary with logFile: " << logFilePath;

    return EXIT_SUCCESS;
}

Answered By – Dominic

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply

(*) Required, Your email will not be published