Skip to content
This repository was archived by the owner on Jun 30, 2025. It is now read-only.

Commit a8e0007

Browse files
authored
Merge pull request #790 from git-hulk/feature/logs-to-stdout
Add the logtostdout and colorlogtostdout flag to allow logging to stdout
2 parents 553ddae + 180b700 commit a8e0007

File tree

6 files changed

+248
-28
lines changed

6 files changed

+248
-28
lines changed

src/glog/logging.h.in

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -428,6 +428,12 @@ typedef void(*CustomPrefixCallback)(std::ostream& s, const LogMessageInfo& l, vo
428428
// Set whether appending a timestamp to the log file name
429429
DECLARE_bool(timestamp_in_logfile_name);
430430

431+
// Set whether log messages go to stdout instead of logfiles
432+
DECLARE_bool(logtostdout);
433+
434+
// Set color messages logged to stdout (if supported by terminal).
435+
DECLARE_bool(colorlogtostdout);
436+
431437
// Set whether log messages go to stderr instead of logfiles
432438
DECLARE_bool(logtostderr);
433439

src/googletest.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,9 @@ static inline void CaptureTestOutput(int fd, const string & filename) {
353353
CHECK(s_captured_streams[fd] == NULL);
354354
s_captured_streams[fd] = new CapturedStream(fd, filename);
355355
}
356+
static inline void CaptureTestStdout() {
357+
CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
358+
}
356359
static inline void CaptureTestStderr() {
357360
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
358361
}
@@ -507,9 +510,13 @@ static inline void WriteToFile(const string& body, const string& file) {
507510
fclose(fp);
508511
}
509512

510-
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
511-
CapturedStream* cap = s_captured_streams[STDERR_FILENO];
512-
CHECK(cap) << ": did you forget CaptureTestStderr()?";
513+
static inline bool MungeAndDiffTest(const string& golden_filename,
514+
CapturedStream* cap) {
515+
if (cap == s_captured_streams[STDOUT_FILENO]) {
516+
CHECK(cap) << ": did you forget CaptureTestStdout()?";
517+
} else {
518+
CHECK(cap) << ": did you forget CaptureTestStderr()?";
519+
}
513520

514521
cap->StopCapture();
515522

@@ -539,6 +546,14 @@ static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
539546
return true;
540547
}
541548

549+
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
550+
return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
551+
}
552+
553+
static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
554+
return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
555+
}
556+
542557
// Save flags used from logging_unittest.cc.
543558
#ifndef HAVE_LIB_GFLAGS
544559
struct FlagSaver {

src/logging.cc

Lines changed: 52 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
122122
"log messages go to stderr in addition to logfiles");
123123
GLOG_DEFINE_bool(colorlogtostderr, false,
124124
"color messages logged to stderr (if supported by terminal)");
125+
GLOG_DEFINE_bool(colorlogtostdout, false,
126+
"color messages logged to stdout (if supported by terminal)");
127+
GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
128+
"log messages go to stdout instead of logfiles");
125129
#ifdef GLOG_OS_LINUX
126130
GLOG_DEFINE_bool(drop_log_memory, true, "Drop in-memory buffers of log contents. "
127131
"Logs can grow very quickly and they are rarely read before they "
@@ -739,43 +743,63 @@ inline void LogDestination::SetEmailLogging(LogSeverity min_severity,
739743
LogDestination::addresses_ = addresses;
740744
}
741745

742-
static void ColoredWriteToStderr(LogSeverity severity,
743-
const char* message, size_t len) {
744-
const GLogColor color =
745-
(LogDestination::terminal_supports_color() && FLAGS_colorlogtostderr) ?
746-
SeverityToColor(severity) : COLOR_DEFAULT;
746+
static void ColoredWriteToStderrOrStdout(FILE* output, LogSeverity severity,
747+
const char* message, size_t len) {
748+
bool is_stdout = (output == stdout);
749+
const GLogColor color = (LogDestination::terminal_supports_color() &&
750+
((!is_stdout && FLAGS_colorlogtostderr) ||
751+
(is_stdout && FLAGS_colorlogtostdout)))
752+
? SeverityToColor(severity)
753+
: COLOR_DEFAULT;
747754

748755
// Avoid using cerr from this module since we may get called during
749756
// exit code, and cerr may be partially or fully destroyed by then.
750757
if (COLOR_DEFAULT == color) {
751-
fwrite(message, len, 1, stderr);
758+
fwrite(message, len, 1, output);
752759
return;
753760
}
754761
#ifdef GLOG_OS_WINDOWS
755-
const HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
762+
const HANDLE output_handle =
763+
GetStdHandle(is_stdout ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
756764

757765
// Gets the current text color.
758766
CONSOLE_SCREEN_BUFFER_INFO buffer_info;
759-
GetConsoleScreenBufferInfo(stderr_handle, &buffer_info);
767+
GetConsoleScreenBufferInfo(output_handle, &buffer_info);
760768
const WORD old_color_attrs = buffer_info.wAttributes;
761769

762770
// We need to flush the stream buffers into the console before each
763771
// SetConsoleTextAttribute call lest it affect the text that is already
764772
// printed but has not yet reached the console.
765-
fflush(stderr);
766-
SetConsoleTextAttribute(stderr_handle,
773+
fflush(output);
774+
SetConsoleTextAttribute(output_handle,
767775
GetColorAttribute(color) | FOREGROUND_INTENSITY);
768-
fwrite(message, len, 1, stderr);
769-
fflush(stderr);
776+
fwrite(message, len, 1, output);
777+
fflush(output);
770778
// Restores the text color.
771-
SetConsoleTextAttribute(stderr_handle, old_color_attrs);
779+
SetConsoleTextAttribute(output_handle, old_color_attrs);
772780
#else
773-
fprintf(stderr, "\033[0;3%sm", GetAnsiColorCode(color));
774-
fwrite(message, len, 1, stderr);
775-
fprintf(stderr, "\033[m"); // Resets the terminal to default.
781+
fprintf(output, "\033[0;3%sm", GetAnsiColorCode(color));
782+
fwrite(message, len, 1, output);
783+
fprintf(output, "\033[m"); // Resets the terminal to default.
776784
#endif // GLOG_OS_WINDOWS
777785
}
778786

787+
static void ColoredWriteToStdout(LogSeverity severity, const char* message,
788+
size_t len) {
789+
FILE* output = stdout;
790+
// We also need to send logs to the stderr when the severity is
791+
// higher or equal to the stderr threshold.
792+
if (severity >= FLAGS_stderrthreshold) {
793+
output = stderr;
794+
}
795+
ColoredWriteToStderrOrStdout(output, severity, message, len);
796+
}
797+
798+
static void ColoredWriteToStderr(LogSeverity severity, const char* message,
799+
size_t len) {
800+
ColoredWriteToStderrOrStdout(stderr, severity, message, len);
801+
}
802+
779803
static void WriteToStderr(const char* message, size_t len) {
780804
// Avoid using cerr from this module since we may get called during
781805
// exit code, and cerr may be partially or fully destroyed by then.
@@ -847,8 +871,9 @@ inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
847871
time_t timestamp,
848872
const char* message,
849873
size_t len) {
850-
851-
if ( FLAGS_logtostderr ) { // global flag: never log to file
874+
if (FLAGS_logtostdout) { // global flag: never log to file
875+
ColoredWriteToStdout(severity, message, len);
876+
} else if (FLAGS_logtostderr) { // global flag: never log to file
852877
ColoredWriteToStderr(severity, message, len);
853878
} else {
854879
for (int i = severity; i >= 0; --i) {
@@ -1812,9 +1837,14 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
18121837
// global flag: never log to file if set. Also -- don't log to a
18131838
// file if we haven't parsed the command line flags to get the
18141839
// program name.
1815-
if (FLAGS_logtostderr || !IsGoogleLoggingInitialized()) {
1816-
ColoredWriteToStderr(data_->severity_,
1817-
data_->message_text_, data_->num_chars_to_log_);
1840+
if (FLAGS_logtostderr || FLAGS_logtostdout || !IsGoogleLoggingInitialized()) {
1841+
if (FLAGS_logtostdout) {
1842+
ColoredWriteToStdout(data_->severity_, data_->message_text_,
1843+
data_->num_chars_to_log_);
1844+
} else {
1845+
ColoredWriteToStderr(data_->severity_, data_->message_text_,
1846+
data_->num_chars_to_log_);
1847+
}
18181848

18191849
// this could be protected by a flag if necessary.
18201850
LogDestination::LogToSinks(data_->severity_,
@@ -1824,7 +1854,6 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
18241854
(data_->num_chars_to_log_ -
18251855
data_->num_prefix_chars_ - 1) );
18261856
} else {
1827-
18281857
// log this message to all log files of severity <= severity_
18291858
LogDestination::LogToAllLogfiles(data_->severity_, logmsgtime_.timestamp(),
18301859
data_->message_text_,
@@ -1862,7 +1891,7 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
18621891
fatal_time = logmsgtime_.timestamp();
18631892
}
18641893

1865-
if (!FLAGS_logtostderr) {
1894+
if (!FLAGS_logtostderr && !FLAGS_logtostdout) {
18661895
for (int i = 0; i < NUM_SEVERITIES; ++i) {
18671896
if (LogDestination::log_destinations_[i]) {
18681897
LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);

src/logging_unittest.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,22 @@ int main(int argc, char **argv) {
242242

243243
FLAGS_logtostderr = false;
244244

245+
FLAGS_logtostdout = true;
246+
FLAGS_stderrthreshold = NUM_SEVERITIES;
247+
CaptureTestStdout();
248+
TestRawLogging();
249+
TestLoggingLevels();
250+
TestLogString();
251+
TestLogSink();
252+
TestLogToString();
253+
TestLogSinkWaitTillSent();
254+
TestCHECK();
255+
TestDCHECK();
256+
TestSTREQ();
257+
EXPECT_TRUE(
258+
MungeAndDiffTestStdout(FLAGS_test_srcdir + "/src/logging_unittest.out"));
259+
FLAGS_logtostdout = false;
260+
245261
TestBasename();
246262
TestBasenameAppendWhenNoTimestamp();
247263
TestTwoProcessesWrite();
@@ -1263,6 +1279,9 @@ class TestWaitingLogSink : public LogSink {
12631279
// Check that LogSink::WaitTillSent can be used in the advertised way.
12641280
// We also do golden-stderr comparison.
12651281
static void TestLogSinkWaitTillSent() {
1282+
// Clear global_messages here to make sure that this test case can be
1283+
// reentered
1284+
global_messages.clear();
12661285
{ TestWaitingLogSink sink;
12671286
// Sleeps give the sink threads time to do all their work,
12681287
// so that we get a reliable log capture to compare to the golden file.

0 commit comments

Comments
 (0)