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