Skip to content

Commit

Permalink
Merge pull request #790 from git-hulk/feature/logs-to-stdout
Browse files Browse the repository at this point in the history
Add the logtostdout and colorlogtostdout flag to allow logging to stdout
  • Loading branch information
sergiud committed Feb 20, 2022
2 parents 553ddae + 180b700 commit a8e0007
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 28 deletions.
6 changes: 6 additions & 0 deletions src/glog/logging.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,12 @@ typedef void(*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l, vo
// Set whether appending a timestamp to the log file name
DECLARE_bool(timestamp_in_logfile_name);

// Set whether log messages go to stdout instead of logfiles
DECLARE_bool(logtostdout);

// Set color messages logged to stdout (if supported by terminal).
DECLARE_bool(colorlogtostdout);

// Set whether log messages go to stderr instead of logfiles
DECLARE_bool(logtostderr);

Expand Down
21 changes: 18 additions & 3 deletions src/googletest.h
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ static inline void CaptureTestOutput(int fd, const string & filename) {
CHECK(s_captured_streams[fd] == NULL);
s_captured_streams[fd] = new CapturedStream(fd, filename);
}
static inline void CaptureTestStdout() {
CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
}
static inline void CaptureTestStderr() {
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
}
Expand Down Expand Up @@ -507,9 +510,13 @@ static inline void WriteToFile(const string& body, const string& file) {
fclose(fp);
}

static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
CapturedStream* cap = s_captured_streams[STDERR_FILENO];
CHECK(cap) << ": did you forget CaptureTestStderr()?";
static inline bool MungeAndDiffTest(const string& golden_filename,
CapturedStream* cap) {
if (cap == s_captured_streams[STDOUT_FILENO]) {
CHECK(cap) << ": did you forget CaptureTestStdout()?";
} else {
CHECK(cap) << ": did you forget CaptureTestStderr()?";
}

cap->StopCapture();

Expand Down Expand Up @@ -539,6 +546,14 @@ static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
return true;
}

static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
}

static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
}

// Save flags used from logging_unittest.cc.
#ifndef HAVE_LIB_GFLAGS
struct FlagSaver {
Expand Down
75 changes: 52 additions & 23 deletions src/logging.cc
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,10 @@ GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
"log messages go to stderr in addition to logfiles");
GLOG_DEFINE_bool(colorlogtostderr, false,
"color messages logged to stderr (if supported by terminal)");
GLOG_DEFINE_bool(colorlogtostdout, false,
"color messages logged to stdout (if supported by terminal)");
GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
"log messages go to stdout instead of logfiles");
#ifdef GLOG_OS_LINUX
GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
"Logs can grow very quickly and they are rarely read before they "
Expand Down Expand Up @@ -739,43 +743,63 @@ inline void LogDestination::SetEmailLogging(LogSeverity min_severity,
LogDestination::addresses_ = addresses;
}

static void ColoredWriteToStderr(LogSeverity severity,
const char* message, size_t len) {
const GLogColor color =
(LogDestination::terminal_supports_color() && FLAGS_colorlogtostderr) ?
SeverityToColor(severity) : COLOR_DEFAULT;
static void ColoredWriteToStderrOrStdout(FILE* output, LogSeverity severity,
const char* message, size_t len) {
bool is_stdout = (output == stdout);
const GLogColor color = (LogDestination::terminal_supports_color() &&
((!is_stdout && FLAGS_colorlogtostderr) ||
(is_stdout && FLAGS_colorlogtostdout)))
? SeverityToColor(severity)
: COLOR_DEFAULT;

// Avoid using cerr from this module since we may get called during
// exit code, and cerr may be partially or fully destroyed by then.
if (COLOR_DEFAULT == color) {
fwrite(message, len, 1, stderr);
fwrite(message, len, 1, output);
return;
}
#ifdef GLOG_OS_WINDOWS
const HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
const HANDLE output_handle =
GetStdHandle(is_stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);

// Gets the current text color.
CONSOLE_SCREEN_BUFFER_INFO buffer_info;
GetConsoleScreenBufferInfo(stderr_handle, &buffer_info);
GetConsoleScreenBufferInfo(output_handle, &buffer_info);
const WORD old_color_attrs = buffer_info.wAttributes;

// We need to flush the stream buffers into the console before each
// SetConsoleTextAttribute call lest it affect the text that is already
// printed but has not yet reached the console.
fflush(stderr);
SetConsoleTextAttribute(stderr_handle,
fflush(output);
SetConsoleTextAttribute(output_handle,
GetColorAttribute(color) | FOREGROUND_INTENSITY);
fwrite(message, len, 1, stderr);
fflush(stderr);
fwrite(message, len, 1, output);
fflush(output);
// Restores the text color.
SetConsoleTextAttribute(stderr_handle, old_color_attrs);
SetConsoleTextAttribute(output_handle, old_color_attrs);
#else
fprintf(stderr, "\033[0;3%sm", GetAnsiColorCode(color));
fwrite(message, len, 1, stderr);
fprintf(stderr, "\033[m"); // Resets the terminal to default.
fprintf(output, "\033[0;3%sm", GetAnsiColorCode(color));
fwrite(message, len, 1, output);
fprintf(output, "\033[m"); // Resets the terminal to default.
#endif // GLOG_OS_WINDOWS
}

static void ColoredWriteToStdout(LogSeverity severity, const char* message,
size_t len) {
FILE* output = stdout;
// We also need to send logs to the stderr when the severity is
// higher or equal to the stderr threshold.
if (severity >= FLAGS_stderrthreshold) {
output = stderr;
}
ColoredWriteToStderrOrStdout(output, severity, message, len);
}

static void ColoredWriteToStderr(LogSeverity severity, const char* message,
size_t len) {
ColoredWriteToStderrOrStdout(stderr, severity, message, len);
}

static void WriteToStderr(const char* message, size_t len) {
// Avoid using cerr from this module since we may get called during
// exit code, and cerr may be partially or fully destroyed by then.
Expand Down Expand Up @@ -847,8 +871,9 @@ inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
time_t timestamp,
const char* message,
size_t len) {

if ( FLAGS_logtostderr ) { // global flag: never log to file
if (FLAGS_logtostdout) { // global flag: never log to file
ColoredWriteToStdout(severity, message, len);
} else if (FLAGS_logtostderr) { // global flag: never log to file
ColoredWriteToStderr(severity, message, len);
} else {
for (int i = severity; i >= 0; --i) {
Expand Down Expand Up @@ -1812,9 +1837,14 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
// global flag: never log to file if set. Also -- don't log to a
// file if we haven't parsed the command line flags to get the
// program name.
if (FLAGS_logtostderr || !IsGoogleLoggingInitialized()) {
ColoredWriteToStderr(data_->severity_,
data_->message_text_, data_->num_chars_to_log_);
if (FLAGS_logtostderr || FLAGS_logtostdout || !IsGoogleLoggingInitialized()) {
if (FLAGS_logtostdout) {
ColoredWriteToStdout(data_->severity_, data_->message_text_,
data_->num_chars_to_log_);
} else {
ColoredWriteToStderr(data_->severity_, data_->message_text_,
data_->num_chars_to_log_);
}

// this could be protected by a flag if necessary.
LogDestination::LogToSinks(data_->severity_,
Expand All @@ -1824,7 +1854,6 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
(data_->num_chars_to_log_ -
data_->num_prefix_chars_ - 1) );
} else {

// log this message to all log files of severity <= severity_
LogDestination::LogToAllLogfiles(data_->severity_, logmsgtime_.timestamp(),
data_->message_text_,
Expand Down Expand Up @@ -1862,7 +1891,7 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
fatal_time = logmsgtime_.timestamp();
}

if (!FLAGS_logtostderr) {
if (!FLAGS_logtostderr && !FLAGS_logtostdout) {
for (int i = 0; i < NUM_SEVERITIES; ++i) {
if (LogDestination::log_destinations_[i]) {
LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
Expand Down
19 changes: 19 additions & 0 deletions src/logging_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,22 @@ int main(int argc, char **argv) {

FLAGS_logtostderr = false;

FLAGS_logtostdout = true;
FLAGS_stderrthreshold = NUM_SEVERITIES;
CaptureTestStdout();
TestRawLogging();
TestLoggingLevels();
TestLogString();
TestLogSink();
TestLogToString();
TestLogSinkWaitTillSent();
TestCHECK();
TestDCHECK();
TestSTREQ();
EXPECT_TRUE(
MungeAndDiffTestStdout(FLAGS_test_srcdir + "/src/logging_unittest.out"));
FLAGS_logtostdout = false;

TestBasename();
TestBasenameAppendWhenNoTimestamp();
TestTwoProcessesWrite();
Expand Down Expand Up @@ -1263,6 +1279,9 @@ class TestWaitingLogSink : public LogSink {
// Check that LogSink::WaitTillSent can be used in the advertised way.
// We also do golden-stderr comparison.
static void TestLogSinkWaitTillSent() {
// Clear global_messages here to make sure that this test case can be
// reentered
global_messages.clear();
{ TestWaitingLogSink sink;
// Sleeps give the sink threads time to do all their work,
// so that we get a reliable log capture to compare to the golden file.
Expand Down
Loading

0 comments on commit a8e0007

Please sign in to comment.