Skip to content

Commit

Permalink
Force a write of all user-space buffered data for stdout in Formatter…
Browse files Browse the repository at this point in the history
…::print (#1012)

* Force a write of all user-space buffered data for stdout in Formatter::print

When application output is connected to pipe a fully-buffered output is used by
default. In this case the logs of application will not be visible for user
until there are enough logs to fill the buffer.

An example where such behaviour can be observed is launching binary ROS executable
from within Android APK. There is not way to connect stdout to TTY and only
pipe can be used. As a result the user cannot see the application output.

The proposed solution is to force flushing of stdout on every line in ROS logger
when a special environment variable is set.

* minor style change
  • Loading branch information
lamerman authored and dirk-thomas committed Mar 15, 2017
1 parent 5d79c24 commit 71905d7
Showing 1 changed file with 27 additions and 0 deletions.
27 changes: 27 additions & 0 deletions tools/rosconsole/src/rosconsole/rosconsole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ std::string g_last_error_message = "Unknown Error";
#endif
const char* g_format_string = "[${severity}] [${time}]: ${message}";

bool g_force_stdout_line_buffered = false;
bool g_stdout_flush_failure_reported = false;

typedef std::map<std::string, std::string> M_string;
M_string g_extra_fixed_tokens;

Expand Down Expand Up @@ -393,6 +396,16 @@ void Formatter::print(void* logger_handle, ::ros::console::Level level, const ch
ss << COLOR_NORMAL;

fprintf(f, "%s\n", ss.str().c_str());

if (g_force_stdout_line_buffered && f == stdout)
{
int flush_result = fflush(f);
if (flush_result != 0 && !g_stdout_flush_failure_reported)
{
g_stdout_flush_failure_reported = true;
fprintf(stderr, "Error: failed to perform fflush on stdout, fflush return code is %d\n", flush_result);
}
}
}

Formatter g_formatter;
Expand Down Expand Up @@ -425,6 +438,20 @@ void initialize()
backend::function_notifyLoggerLevelsChanged = notifyLoggerLevelsChanged;
backend::function_print = _print;

std::string line_buffered;
if (get_environment_variable(line_buffered, "ROSCONSOLE_STDOUT_LINE_BUFFERED"))
{
if (line_buffered == "1")
{
g_force_stdout_line_buffered = true;
}
else if (line_buffered != "0")
{
fprintf(stderr, "Warning: unexpected value %s specified for ROSCONSOLE_STDOUT_LINE_BUFFERED. Default value 0 "
"will be used. Valid values are 1 or 0.\n", line_buffered.c_str());
}
}

::ros::console::impl::initialize();
g_initialized = true;
}
Expand Down

0 comments on commit 71905d7

Please sign in to comment.