Use gflags ALIAS instead of ${gflags_XXX} vars
[platform/upstream/glog.git] / src / logging.cc
index 8c64274..0b5e6ee 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "utilities.h"
 
+#include <algorithm>
 #include <assert.h>
 #include <iomanip>
 #include <string>
@@ -68,7 +69,6 @@
 
 using std::string;
 using std::vector;
-using std::ostrstream;
 using std::setw;
 using std::setfill;
 using std::hex;
@@ -76,7 +76,21 @@ using std::dec;
 using std::min;
 using std::ostream;
 using std::ostringstream;
-using std::strstream;
+
+using std::FILE;
+using std::fwrite;
+using std::fclose;
+using std::fflush;
+using std::fprintf;
+using std::perror;
+
+#ifdef __QNX__
+using std::fdopen;
+#endif
+
+#ifdef _WIN32
+#define fdopen _fdopen
+#endif
 
 // There is no thread annotation support.
 #define EXCLUSIVE_LOCKS_REQUIRED(mu)
@@ -89,15 +103,17 @@ static bool BoolFromEnv(const char *varname, bool defval) {
   return memchr("tTyY1\0", valstr[0], 6) != NULL;
 }
 
-DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
-            "log messages go to stderr instead of logfiles");
-DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
-            "log messages go to stderr in addition to logfiles");
+GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
+                 "log messages go to stderr instead of logfiles");
+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)");
 #ifdef OS_LINUX
-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 "
-            "need to be evicted from memory. Instead, drop them from memory "
-            "as soon as they are flushed to disk.");
+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 "
+                 "need to be evicted from memory. Instead, drop them from memory "
+                 "as soon as they are flushed to disk.");
 _START_GOOGLE_NAMESPACE_
 namespace logging {
 static const int64 kPageSize = getpagesize();
@@ -111,29 +127,29 @@ _END_GOOGLE_NAMESPACE_
 // The default is ERROR instead of FATAL so that users can see problems
 // when they run a program without having to look in another file.
 DEFINE_int32(stderrthreshold,
-             GOOGLE_NAMESPACE::ERROR,
+             GOOGLE_NAMESPACE::GLOG_ERROR,
              "log messages at or above this level are copied to stderr in "
              "addition to logfiles.  This flag obsoletes --alsologtostderr.");
 
-DEFINE_string(alsologtoemail, "",
-              "log messages go to these email addresses "
-              "in addition to logfiles");
-DEFINE_bool(log_prefix, true,
-            "Prepend the log prefix to the start of each log line");
-DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
-             "actually get logged anywhere");
-DEFINE_int32(logbuflevel, 0,
-             "Buffer log messages logged at this level or lower"
-             " (-1 means don't buffer; 0 means buffer INFO only;"
-             " ...)");
-DEFINE_int32(logbufsecs, 30,
-             "Buffer log messages for at most this many seconds");
-DEFINE_int32(logemaillevel, 999,
-             "Email log messages logged at this level or higher"
-             " (0 means email all; 3 means email FATAL only;"
-             " ...)");
-DEFINE_string(logmailer, "/bin/mail",
-              "Mailer used to send logging email");
+GLOG_DEFINE_string(alsologtoemail, "",
+                   "log messages go to these email addresses "
+                   "in addition to logfiles");
+GLOG_DEFINE_bool(log_prefix, true,
+                 "Prepend the log prefix to the start of each log line");
+GLOG_DEFINE_int32(minloglevel, 0, "Messages logged at a lower level than this don't "
+                  "actually get logged anywhere");
+GLOG_DEFINE_int32(logbuflevel, 0,
+                  "Buffer log messages logged at this level or lower"
+                  " (-1 means don't buffer; 0 means buffer INFO only;"
+                  " ...)");
+GLOG_DEFINE_int32(logbufsecs, 30,
+                  "Buffer log messages for at most this many seconds");
+GLOG_DEFINE_int32(logemaillevel, 999,
+                  "Email log messages logged at this level or higher"
+                  " (0 means email all; 3 means email FATAL only;"
+                  " ...)");
+GLOG_DEFINE_string(logmailer, "/bin/mail",
+                   "Mailer used to send logging email");
 
 // Compute the default value for --log_dir
 static const char* DefaultLogDir() {
@@ -149,25 +165,63 @@ static const char* DefaultLogDir() {
   return "";
 }
 
-DEFINE_string(log_dir, DefaultLogDir(),
-              "If specified, logfiles are written into this directory instead "
-              "of the default logging directory.");
-DEFINE_string(log_link, "", "Put additional links to the log "
-              "files in this directory");
+GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
 
-DEFINE_int32(max_log_size, 1800,
-             "approx. maximum log file size (in MB). A value of 0 will "
-             "be silently overridden to 1.");
+GLOG_DEFINE_string(log_dir, DefaultLogDir(),
+                   "If specified, logfiles are written into this directory instead "
+                   "of the default logging directory.");
+GLOG_DEFINE_string(log_link, "", "Put additional links to the log "
+                   "files in this directory");
 
-DEFINE_bool(stop_logging_if_full_disk, false,
-            "Stop attempting to log to disk if the disk is full.");
+GLOG_DEFINE_int32(max_log_size, 1800,
+                  "approx. maximum log file size (in MB). A value of 0 will "
+                  "be silently overridden to 1.");
 
-DEFINE_string(log_backtrace_at, "",
-              "Emit a backtrace when logging at file:linenum.");
+GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
+                 "Stop attempting to log to disk if the disk is full.");
+
+GLOG_DEFINE_string(log_backtrace_at, "",
+                   "Emit a backtrace when logging at file:linenum.");
 
 // TODO(hamaji): consider windows
 #define PATH_SEPARATOR '/'
 
+#ifndef HAVE_PREAD
+#if defined(OS_WINDOWS)
+#include <BaseTsd.h>
+#define ssize_t SSIZE_T
+#endif
+static ssize_t pread(int fd, void* buf, size_t count, off_t offset) {
+  off_t orig_offset = lseek(fd, 0, SEEK_CUR);
+  if (orig_offset == (off_t)-1)
+    return -1;
+  if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
+    return -1;
+  ssize_t len = read(fd, buf, count);
+  if (len < 0)
+    return len;
+  if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
+    return -1;
+  return len;
+}
+#endif  // !HAVE_PREAD
+
+#ifndef HAVE_PWRITE
+static ssize_t pwrite(int fd, void* buf, size_t count, off_t offset) {
+  off_t orig_offset = lseek(fd, 0, SEEK_CUR);
+  if (orig_offset == (off_t)-1)
+    return -1;
+  if (lseek(fd, offset, SEEK_CUR) == (off_t)-1)
+    return -1;
+  ssize_t len = write(fd, buf, count);
+  if (len < 0)
+    return len;
+  if (lseek(fd, orig_offset, SEEK_SET) == (off_t)-1)
+    return -1;
+  return len;
+}
+#endif  // !HAVE_PWRITE
+
 static void GetHostName(string* hostname) {
 #if defined(HAVE_SYS_UTSNAME_H)
   struct utsname buf;
@@ -190,13 +244,126 @@ static void GetHostName(string* hostname) {
 #endif
 }
 
+// Returns true iff terminal supports using colors in output.
+static bool TerminalSupportsColor() {
+  bool term_supports_color = false;
+#ifdef OS_WINDOWS
+  // on Windows TERM variable is usually not set, but the console does
+  // support colors.
+  term_supports_color = true;
+#else
+  // On non-Windows platforms, we rely on the TERM variable.
+  const char* const term = getenv("TERM");
+  if (term != NULL && term[0] != '\0') {
+    term_supports_color =
+      !strcmp(term, "xterm") ||
+      !strcmp(term, "xterm-color") ||
+      !strcmp(term, "xterm-256color") ||
+      !strcmp(term, "screen-256color") ||
+      !strcmp(term, "screen") ||
+      !strcmp(term, "linux") ||
+      !strcmp(term, "cygwin");
+  }
+#endif
+  return term_supports_color;
+}
+
 _START_GOOGLE_NAMESPACE_
 
+enum GLogColor {
+  COLOR_DEFAULT,
+  COLOR_RED,
+  COLOR_GREEN,
+  COLOR_YELLOW
+};
+
+static GLogColor SeverityToColor(LogSeverity severity) {
+  assert(severity >= 0 && severity < NUM_SEVERITIES);
+  GLogColor color = COLOR_DEFAULT;
+  switch (severity) {
+  case GLOG_INFO:
+    color = COLOR_DEFAULT;
+    break;
+  case GLOG_WARNING:
+    color = COLOR_YELLOW;
+    break;
+  case GLOG_ERROR:
+  case GLOG_FATAL:
+    color = COLOR_RED;
+    break;
+  default:
+    // should never get here.
+    assert(false);
+  }
+  return color;
+}
+
+#ifdef OS_WINDOWS
+
+// Returns the character attribute for the given color.
+WORD GetColorAttribute(GLogColor color) {
+  switch (color) {
+    case COLOR_RED:    return FOREGROUND_RED;
+    case COLOR_GREEN:  return FOREGROUND_GREEN;
+    case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN;
+    default:           return 0;
+  }
+}
+
+#else
+
+// Returns the ANSI color code for the given color.
+const char* GetAnsiColorCode(GLogColor color) {
+  switch (color) {
+  case COLOR_RED:     return "1";
+  case COLOR_GREEN:   return "2";
+  case COLOR_YELLOW:  return "3";
+  case COLOR_DEFAULT:  return "";
+  };
+  return NULL; // stop warning about return type.
+}
+
+#endif  // OS_WINDOWS
+
 // Safely get max_log_size, overriding to 1 if it somehow gets defined as 0
 static int32 MaxLogSize() {
   return (FLAGS_max_log_size > 0 ? FLAGS_max_log_size : 1);
 }
 
+// An arbitrary limit on the length of a single log message.  This
+// is so that streaming can be done more efficiently.
+const size_t LogMessage::kMaxLogMessageLen = 30000;
+
+struct LogMessage::LogMessageData  {
+  LogMessageData();
+
+  int preserved_errno_;      // preserved errno
+  // Buffer space; contains complete message text.
+  char message_text_[LogMessage::kMaxLogMessageLen+1];
+  LogStream stream_;
+  char severity_;      // What level is this LogMessage logged at?
+  int line_;                 // line number where logging call is.
+  void (LogMessage::*send_method_)();  // Call this in destructor to send
+  union {  // At most one of these is used: union to keep the size low.
+    LogSink* sink_;             // NULL or sink to send message to
+    std::vector<std::string>* outvec_; // NULL or vector to push message onto
+    std::string* message_;             // NULL or string to write message into
+  };
+  time_t timestamp_;            // Time of creation of LogMessage
+  struct ::tm tm_time_;         // Time of creation of LogMessage
+  size_t num_prefix_chars_;     // # of chars of prefix in this message
+  size_t num_chars_to_log_;     // # of chars of msg to send to log
+  size_t num_chars_to_syslog_;  // # of chars of msg to send to syslog
+  const char* basename_;        // basename of file that called LOG
+  const char* fullname_;        // fullname of file that called LOG
+  bool has_been_flushed_;       // false => data has not been flushed
+  bool first_fatal_;            // true => this was first fatal msg
+
+ private:
+  LogMessageData(const LogMessageData&);
+  void operator=(const LogMessageData&);
+};
+
 // A mutex that allows only one thread to log at a time, to keep things from
 // getting jumbled.  Some other very uncommon logging operations (like
 // changing the destination file for log messages of a given severity) also
@@ -278,7 +445,7 @@ class LogFileObject : public base::Logger {
   // Actually create a logfile using the value of base_filename_ and the
   // supplied argument time_pid_string
   // REQUIRES: lock_ is held
-  bool CreateLogfile(const char* time_pid_string);
+  bool CreateLogfile(const string& time_pid_string);
 };
 
 }  // namespace
@@ -311,8 +478,13 @@ class LogDestination {
   static const int kNetworkBytes = 1400;
 
   static const string& hostname();
- private:
+  static const bool& terminal_supports_color() {
+    return terminal_supports_color_;
+  }
 
+  static void DeleteLogDestinations();
+
+ private:
   LogDestination(LogSeverity severity, const char* base_filename);
   ~LogDestination() { }
 
@@ -359,6 +531,7 @@ class LogDestination {
   static LogSeverity email_logging_severity_;
   static string addresses_;
   static string hostname_;
+  static bool terminal_supports_color_;
 
   // arbitrary global logging destinations.
   static vector<LogSink*>* sinks_;
@@ -380,6 +553,7 @@ string LogDestination::hostname_;
 
 vector<LogSink*>* LogDestination::sinks_ = NULL;
 Mutex LogDestination::sink_mutex_;
+bool LogDestination::terminal_supports_color_ = TerminalSupportsColor();
 
 /* static */
 const string& LogDestination::hostname() {
@@ -402,7 +576,7 @@ inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
   // assume we have the log_mutex or we simply don't care
   // about it
   for (int i = min_severity; i < NUM_SEVERITIES; i++) {
-    LogDestination* log = log_destination(i);
+    LogDestination* log = log_destinations_[i];
     if (log != NULL) {
       // Flush the base fileobject_ logger directly instead of going
       // through any wrappers to reduce chance of deadlock.
@@ -500,16 +674,53 @@ 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;
+
+  // 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);
+    return;
+  }
+#ifdef OS_WINDOWS
+  const HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
+
+  // Gets the current text color.
+  CONSOLE_SCREEN_BUFFER_INFO buffer_info;
+  GetConsoleScreenBufferInfo(stderr_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,
+                          GetColorAttribute(color) | FOREGROUND_INTENSITY);
+  fwrite(message, len, 1, stderr);
+  fflush(stderr);
+  // Restores the text color.
+  SetConsoleTextAttribute(stderr_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.
+#endif  // OS_WINDOWS
+}
+
 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.
-  write(STDERR_FILENO, message, len);
+  fwrite(message, len, 1, stderr);
 }
 
 inline void LogDestination::MaybeLogToStderr(LogSeverity severity,
                                             const char* message, size_t len) {
   if ((severity >= FLAGS_stderrthreshold) || FLAGS_alsologtostderr) {
-    WriteToStderr(message, len);
+    ColoredWriteToStderr(severity, message, len);
 #ifdef OS_WINDOWS
     // On Windows, also output to the debugger
     ::OutputDebugStringA(string(message,len).c_str());
@@ -558,12 +769,12 @@ inline void LogDestination::LogToAllLogfiles(LogSeverity severity,
                                              const char* message,
                                              size_t len) {
 
-  if ( FLAGS_logtostderr )            // global flag: never log to file
-    WriteToStderr(message, len);
-  else
+  if ( FLAGS_logtostderr ) {           // global flag: never log to file
+    ColoredWriteToStderr(severity, message, len);
+  } else {
     for (int i = severity; i >= 0; --i)
       LogDestination::MaybeLogToLogfile(i, timestamp, message, len);
-
+  }
 }
 
 inline void LogDestination::LogToSinks(LogSeverity severity,
@@ -607,6 +818,16 @@ inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
   return log_destinations_[severity];
 }
 
+void LogDestination::DeleteLogDestinations() {
+  for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {
+    delete log_destinations_[severity];
+    log_destinations_[severity] = NULL;
+  }
+  MutexLock l(&sink_mutex_);
+  delete sinks_;
+  sinks_ = NULL;
+}
+
 namespace {
 
 LogFileObject::LogFileObject(LogSeverity severity,
@@ -681,11 +902,11 @@ void LogFileObject::FlushUnlocked(){
   next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
 }
 
-bool LogFileObject::CreateLogfile(const char* time_pid_string) {
+bool LogFileObject::CreateLogfile(const string& time_pid_string) {
   string string_filename = base_filename_+filename_extension_+
                            time_pid_string;
   const char* filename = string_filename.c_str();
-  int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0664);
+  int fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, FLAGS_logfile_mode);
   if (fd == -1) return false;
 #ifdef HAVE_FCNTL
   // Mark the file close-on-exec. We don't really care if this fails
@@ -714,19 +935,25 @@ bool LogFileObject::CreateLogfile(const char* time_pid_string) {
     linkpath += linkname;
     unlink(linkpath.c_str());                    // delete old one if it exists
 
+#if defined(OS_WINDOWS)
+    // TODO(hamaji): Create lnk file on Windows?
+#elif defined(HAVE_UNISTD_H)
     // We must have unistd.h.
-#ifdef HAVE_UNISTD_H
     // Make the symlink be relative (in the same dir) so that if the
     // entire log directory gets relocated the link is still valid.
     const char *linkdest = slash ? (slash + 1) : filename;
-    symlink(linkdest, linkpath.c_str());         // silently ignore failures
+    if (symlink(linkdest, linkpath.c_str()) != 0) {
+      // silently ignore failures
+    }
 
     // Make an additional link to the log file in a place specified by
     // FLAGS_log_link, if indicated
     if (!FLAGS_log_link.empty()) {
       linkpath = FLAGS_log_link + "/" + linkname;
       unlink(linkpath.c_str());                  // delete old one if it exists
-      symlink(filename, linkpath.c_str());       // silently ignore failures
+      if (symlink(filename, linkpath.c_str()) != 0) {
+        // silently ignore failures
+      }
     }
 #endif
   }
@@ -745,7 +972,8 @@ void LogFileObject::Write(bool force_flush,
     return;
   }
 
-  if (static_cast<int>(file_length_ >> 20) >= MaxLogSize()) {
+  if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||
+      PidHasChanged()) {
     if (file_ != NULL) fclose(file_);
     file_ = NULL;
     file_length_ = bytes_since_flush_ = 0;
@@ -764,24 +992,24 @@ void LogFileObject::Write(bool force_flush,
     localtime_r(&timestamp, &tm_time);
 
     // The logfile's filename will have the date/time & pid in it
-    char time_pid_string[256];  // More than enough chars for time, pid, \0
-    ostrstream time_pid_stream(time_pid_string, sizeof(time_pid_string));
+    ostringstream time_pid_stream;
     time_pid_stream.fill('0');
     time_pid_stream << 1900+tm_time.tm_year
-                   << setw(2) << 1+tm_time.tm_mon
-                   << setw(2) << tm_time.tm_mday
-                   << '-'
-                   << setw(2) << tm_time.tm_hour
-                   << setw(2) << tm_time.tm_min
-                   << setw(2) << tm_time.tm_sec
-                   << '.'
-                   << GetMainThreadPid()
-                   << '\0';
+                    << setw(2) << 1+tm_time.tm_mon
+                    << setw(2) << tm_time.tm_mday
+                    << '-'
+                    << setw(2) << tm_time.tm_hour
+                    << setw(2) << tm_time.tm_min
+                    << setw(2) << tm_time.tm_sec
+                    << '.'
+                    << GetMainThreadPid();
+    const string& time_pid_string = time_pid_stream.str();
 
     if (base_filename_selected_) {
       if (!CreateLogfile(time_pid_string)) {
         perror("Could not create log file");
-        fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n", time_pid_string);
+        fprintf(stderr, "COULD NOT CREATE LOGFILE '%s'!\n",
+                time_pid_string.c_str());
         return;
       }
     } else {
@@ -829,15 +1057,14 @@ void LogFileObject::Write(bool force_flush,
       // If we never succeeded, we have to give up
       if ( success == false ) {
         perror("Could not create logging file");
-        fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!", time_pid_string);
+        fprintf(stderr, "COULD NOT CREATE A LOGGINGFILE %s!",
+                time_pid_string.c_str());
         return;
       }
     }
 
     // Write a header message into the log file
-    char file_header_string[512];  // Enough chars for time and binary info
-    ostrstream file_header_stream(file_header_string,
-                                  sizeof(file_header_string));
+    ostringstream file_header_stream;
     file_header_stream.fill('0');
     file_header_stream << "Log file created at: "
                        << 1900+tm_time.tm_year << '/'
@@ -850,10 +1077,11 @@ void LogFileObject::Write(bool force_flush,
                        << "Running on machine: "
                        << LogDestination::hostname() << '\n'
                        << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu "
-                       << "threadid file:line] msg" << '\n'
-                       << '\0';
-    int header_len = strlen(file_header_string);
-    fwrite(file_header_string, 1, header_len, file_);
+                       << "threadid file:line] msg" << '\n';
+    const string& file_header_string = file_header_stream.str();
+
+    const int header_len = file_header_string.size();
+    fwrite(file_header_string.data(), 1, header_len, file_);
     file_length_ += header_len;
     bytes_since_flush_ += header_len;
   }
@@ -901,9 +1129,6 @@ void LogFileObject::Write(bool force_flush,
 
 }  // namespace
 
-// An arbitrary limit on the length of a single log message.  This
-// is so that streaming can be done more efficiently.
-const size_t LogMessage::kMaxLogMessageLen = 30000;
 
 // Static log data space to avoid alloc failures in a LOG(FATAL)
 //
@@ -914,55 +1139,55 @@ const size_t LogMessage::kMaxLogMessageLen = 30000;
 static Mutex fatal_msg_lock;
 static CrashReason crash_reason;
 static bool fatal_msg_exclusive = true;
-static char fatal_msg_buf_exclusive[LogMessage::kMaxLogMessageLen+1];
-static char fatal_msg_buf_shared[LogMessage::kMaxLogMessageLen+1];
-static LogMessage::LogStream fatal_msg_stream_exclusive(
-    fatal_msg_buf_exclusive, LogMessage::kMaxLogMessageLen, 0);
-static LogMessage::LogStream fatal_msg_stream_shared(
-    fatal_msg_buf_shared, LogMessage::kMaxLogMessageLen, 0);
-LogMessage::LogMessageData LogMessage::fatal_msg_data_exclusive_;
-LogMessage::LogMessageData LogMessage::fatal_msg_data_shared_;
+static LogMessage::LogMessageData fatal_msg_data_exclusive;
+static LogMessage::LogMessageData fatal_msg_data_shared;
 
-LogMessage::LogMessageData::~LogMessageData() {
-  delete[] buf_;
-  delete stream_alloc_;
+LogMessage::LogMessageData::LogMessageData()
+  : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
 }
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
-                      int ctr, void (LogMessage::*send_method)()) {
+                       int ctr, void (LogMessage::*send_method)())
+    : allocated_(NULL) {
   Init(file, line, severity, send_method);
-  data_->stream_->set_ctr(ctr);
+  data_->stream_.set_ctr(ctr);
 }
 
 LogMessage::LogMessage(const char* file, int line,
-                       const CheckOpString& result) {
-  Init(file, line, FATAL, &LogMessage::SendToLog);
+                       const CheckOpString& result)
+    : allocated_(NULL) {
+  Init(file, line, GLOG_FATAL, &LogMessage::SendToLog);
   stream() << "Check failed: " << (*result.str_) << " ";
 }
 
-LogMessage::LogMessage(const char* file, int line) {
-  Init(file, line, INFO, &LogMessage::SendToLog);
+LogMessage::LogMessage(const char* file, int line)
+    : allocated_(NULL) {
+  Init(file, line, GLOG_INFO, &LogMessage::SendToLog);
 }
 
-LogMessage::LogMessage(const char* file, int line, LogSeverity severity) {
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
+    : allocated_(NULL) {
   Init(file, line, severity, &LogMessage::SendToLog);
 }
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
-                       LogSink* sink, bool also_send_to_log) {
+                       LogSink* sink, bool also_send_to_log)
+    : allocated_(NULL) {
   Init(file, line, severity, also_send_to_log ? &LogMessage::SendToSinkAndLog :
                                                 &LogMessage::SendToSink);
   data_->sink_ = sink;  // override Init()'s setting to NULL
 }
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
-                       vector<string> *outvec) {
+                       vector<string> *outvec)
+    : allocated_(NULL) {
   Init(file, line, severity, &LogMessage::SaveOrSendToLog);
   data_->outvec_ = outvec; // override Init()'s setting to NULL
 }
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
-                       string *message) {
+                       string *message)
+    : allocated_(NULL) {
   Init(file, line, severity, &LogMessage::WriteToStringAndLog);
   data_->message_ = message;  // override Init()'s setting to NULL
 }
@@ -972,30 +1197,20 @@ void LogMessage::Init(const char* file,
                       LogSeverity severity,
                       void (LogMessage::*send_method)()) {
   allocated_ = NULL;
-  if (severity != FATAL || !exit_on_dfatal) {
+  if (severity != GLOG_FATAL || !exit_on_dfatal) {
     allocated_ = new LogMessageData();
     data_ = allocated_;
-    data_->buf_ = new char[kMaxLogMessageLen+1];
-    data_->message_text_ = data_->buf_;
-    data_->stream_alloc_ =
-        new LogStream(data_->message_text_, kMaxLogMessageLen, 0);
-    data_->stream_ = data_->stream_alloc_;
     data_->first_fatal_ = false;
   } else {
     MutexLock l(&fatal_msg_lock);
     if (fatal_msg_exclusive) {
       fatal_msg_exclusive = false;
-      data_ = &fatal_msg_data_exclusive_;
-      data_->message_text_ = fatal_msg_buf_exclusive;
-      data_->stream_ = &fatal_msg_stream_exclusive;
+      data_ = &fatal_msg_data_exclusive;
       data_->first_fatal_ = true;
     } else {
-      data_ = &fatal_msg_data_shared_;
-      data_->message_text_ = fatal_msg_buf_shared;
-      data_->stream_ = &fatal_msg_stream_shared;
+      data_ = &fatal_msg_data_shared;
       data_->first_fatal_ = false;
     }
-    data_->stream_alloc_ = NULL;
   }
 
   stream().fill('0');
@@ -1036,7 +1251,7 @@ void LogMessage::Init(const char* file,
              << ' '
              << data_->basename_ << ':' << data_->line_ << "] ";
   }
-  data_->num_prefix_chars_ = data_->stream_->pcount();
+  data_->num_prefix_chars_ = data_->stream_.pcount();
 
   if (!FLAGS_log_backtrace_at.empty()) {
     char fileline[128];
@@ -1056,13 +1271,21 @@ LogMessage::~LogMessage() {
   delete allocated_;
 }
 
+int LogMessage::preserved_errno() const {
+  return data_->preserved_errno_;
+}
+
+ostream& LogMessage::stream() {
+  return data_->stream_;
+}
+
 // Flush buffered message, called by the destructor, or any other function
 // that needs to synchronize the log.
 void LogMessage::Flush() {
   if (data_->has_been_flushed_ || data_->severity_ < FLAGS_minloglevel)
     return;
 
-  data_->num_chars_to_log_ = data_->stream_->pcount();
+  data_->num_chars_to_log_ = data_->stream_.pcount();
   data_->num_chars_to_syslog_ =
     data_->num_chars_to_log_ - data_->num_prefix_chars_;
 
@@ -1112,7 +1335,7 @@ void LogMessage::Flush() {
 
 // Copy of first FATAL log message so that we can print it out again
 // after all the stack traces.  To preserve legacy behavior, we don't
-// use fatal_msg_buf_exclusive.
+// use fatal_msg_data_exclusive.
 static time_t fatal_time;
 static char fatal_message[256];
 
@@ -1120,10 +1343,10 @@ void ReprintFatalMessage() {
   if (fatal_message[0]) {
     const int n = strlen(fatal_message);
     if (!FLAGS_logtostderr) {
-      // Also write to stderr
+      // Also write to stderr (don't color to avoid terminal checks)
       WriteToStderr(fatal_message, n);
     }
-    LogDestination::LogToAllLogfiles(ERROR, fatal_time, fatal_message, n);
+    LogDestination::LogToAllLogfiles(GLOG_ERROR, fatal_time, fatal_message, n);
   }
 }
 
@@ -1149,7 +1372,8 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
   // file if we haven't parsed the command line flags to get the
   // program name.
   if (FLAGS_logtostderr || !IsGoogleLoggingInitialized()) {
-    WriteToStderr(data_->message_text_, data_->num_chars_to_log_);
+    ColoredWriteToStderr(data_->severity_,
+                         data_->message_text_, data_->num_chars_to_log_);
 
     // this could be protected by a flag if necessary.
     LogDestination::LogToSinks(data_->severity_,
@@ -1181,7 +1405,7 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
   // If we log a FATAL message, flush all the log destinations, then toss
   // a signal for others to catch. We leave the logs in a state that
   // someone else can use them (as long as they flush afterwards)
-  if (data_->severity_ == FATAL && exit_on_dfatal) {
+  if (data_->severity_ == GLOG_FATAL && exit_on_dfatal) {
     if (data_->first_fatal_) {
       // Store crash information so that it is accessible from within signal
       // handlers that may be invoked later.
@@ -1212,17 +1436,19 @@ void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
     LogDestination::WaitForSinks(data_);
 
     const char* message = "*** Check failure stack trace: ***\n";
-    write(STDERR_FILENO, message, strlen(message));
+    if (write(STDERR_FILENO, message, strlen(message)) < 0) {
+      // Ignore errors.
+    }
     Fail();
   }
 }
 
 void LogMessage::RecordCrashReason(
     glog_internal_namespace_::CrashReason* reason) {
-  reason->filename = fatal_msg_data_exclusive_.fullname_;
-  reason->line_number = fatal_msg_data_exclusive_.line_;
-  reason->message = fatal_msg_buf_exclusive +
-                    fatal_msg_data_exclusive_.num_prefix_chars_;
+  reason->filename = fatal_msg_data_exclusive.fullname_;
+  reason->line_number = fatal_msg_data_exclusive.line_;
+  reason->message = fatal_msg_data_exclusive.message_text_ +
+                    fatal_msg_data_exclusive.num_prefix_chars_;
 #ifdef HAVE_STACKTRACE
   // Retrieve the stack trace, omitting the logging frames that got us here.
   reason->depth = GetStackTrace(reason->stack, ARRAYSIZE(reason->stack), 4);
@@ -1231,25 +1457,31 @@ void LogMessage::RecordCrashReason(
 #endif
 }
 
+#ifdef HAVE___ATTRIBUTE__
+# define ATTRIBUTE_NORETURN __attribute__((noreturn))
+#else
+# define ATTRIBUTE_NORETURN
+#endif
+
+static void logging_fail() ATTRIBUTE_NORETURN;
+
 static void logging_fail() {
 #if defined(_DEBUG) && defined(_MSC_VER)
   // When debugging on windows, avoid the obnoxious dialog and make
   // it possible to continue past a LOG(FATAL) in the debugger
-  _asm int 3
+  __debugbreak();
 #else
   abort();
 #endif
 }
 
-#ifdef HAVE___ATTRIBUTE__
+typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
+
 GOOGLE_GLOG_DLL_DECL
-void (*g_logging_fail_func)() __attribute__((noreturn)) = &logging_fail;
-#else
-GOOGLE_GLOG_DLL_DECL void (*g_logging_fail_func)() = &logging_fail;
-#endif
+logging_fail_func_t g_logging_fail_func = &logging_fail;
 
 void InstallFailureFunction(void (*fail_func)()) {
-  g_logging_fail_func = fail_func;
+  g_logging_fail_func = (logging_fail_func_t)fail_func;
 }
 
 void LogMessage::Fail() {
@@ -1343,8 +1575,13 @@ int64 LogMessage::num_messages(int severity) {
 // Output the COUNTER value. This is only valid if ostream is a
 // LogStream.
 ostream& operator<<(ostream &os, const PRIVATE_Counter&) {
+#ifdef DISABLE_RTTI
+  LogMessage::LogStream *log = static_cast<LogMessage::LogStream*>(&os);
+#else
   LogMessage::LogStream *log = dynamic_cast<LogMessage::LogStream*>(&os);
-  CHECK(log == log->self());
+#endif
+  CHECK(log && log == log->self())
+      << "You must not use COUNTER with non-glog ostream";
   os << log->ctr();
   return os;
 }
@@ -1358,9 +1595,8 @@ ErrnoLogMessage::ErrnoLogMessage(const char* file, int line,
 ErrnoLogMessage::~ErrnoLogMessage() {
   // Don't access errno directly because it may have been altered
   // while streaming the message.
-  char buf[100];
-  posix_strerror_r(preserved_errno(), buf, sizeof(buf));
-  stream() << ": " << buf << " [" << preserved_errno() << "]";
+  stream() << ": " << StrError(preserved_errno()) << " ["
+           << preserved_errno() << "]";
 }
 
 void FlushLogFiles(LogSeverity min_severity) {
@@ -1489,13 +1725,11 @@ static bool SendEmailInternal(const char*dest, const char *subject,
       bool ok = pclose(pipe) != -1;
       if ( !ok ) {
         if ( use_logging ) {
-          char buf[100];
-          posix_strerror_r(errno, buf, sizeof(buf));
-          LOG(ERROR) << "Problems sending mail to " << dest << ": " << buf;
+          LOG(ERROR) << "Problems sending mail to " << dest << ": "
+                     << StrError(errno);
         } else {
-          char buf[100];
-          posix_strerror_r(errno, buf, sizeof(buf));
-          fprintf(stderr, "Problems sending mail to %s: %s\n", dest, buf);
+          fprintf(stderr, "Problems sending mail to %s: %s\n",
+                  dest, StrError(errno).c_str());
         }
       }
       return ok;
@@ -1542,7 +1776,7 @@ static void GetTempDirectories(vector<string>* list) {
     "/tmp",
   };
 
-  for (int i = 0; i < ARRAYSIZE(candidates); i++) {
+  for (size_t i = 0; i < ARRAYSIZE(candidates); i++) {
     const char *d = candidates[i];
     if (!d) continue;  // Empty env var
 
@@ -1617,8 +1851,11 @@ void TruncateLogFile(const char *path, int64 limit, int64 keep) {
   int64 read_offset, write_offset;
   // Don't follow symlinks unless they're our own fd symlinks in /proc
   int flags = O_RDWR;
+  // TODO(hamaji): Support other environments.
+#ifdef OS_LINUX
   const char *procfd_prefix = "/proc/self/fd/";
   if (strncmp(procfd_prefix, path, strlen(procfd_prefix))) flags |= O_NOFOLLOW;
+#endif
 
   int fd = open(path, flags);
   if (fd == -1) {
@@ -1629,9 +1866,9 @@ void TruncateLogFile(const char *path, int64 limit, int64 keep) {
       // rather scary.
       // Instead just truncate the file to something we can manage
       if (truncate(path, 0) == -1) {
-       PLOG(ERROR) << "Unable to truncate " << path;
+        PLOG(ERROR) << "Unable to truncate " << path;
       } else {
-       LOG(ERROR) << "Truncated " << path << " due to EFBIG error";
+        LOG(ERROR) << "Truncated " << path << " due to EFBIG error";
       }
     } else {
       PLOG(ERROR) << "Unable to open " << path;
@@ -1703,11 +1940,11 @@ void TruncateStdoutStderr() {
     bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2));               \
     if (equal == expected) return NULL;                                 \
     else {                                                              \
-      strstream ss;                                                     \
+      ostringstream ss;                                                 \
       if (!s1) s1 = "";                                                 \
       if (!s2) s2 = "";                                                 \
       ss << #name " failed: " << names << " (" << s1 << " vs. " << s2 << ")"; \
-      return new string(ss.str(), ss.pcount());                         \
+      return new string(ss.str());                                      \
     }                                                                   \
   }
 DEFINE_CHECK_STROP_IMPL(CHECK_STREQ, strcmp, true)
@@ -1755,7 +1992,7 @@ int posix_strerror_r(int err, char *buf, size_t len) {
     } else {
       buf[0] = '\000';
 #if defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
-      if (reinterpret_cast<int>(rc) < sys_nerr) {
+      if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
         // This means an error on MacOSX or FreeBSD.
         return -1;
       }
@@ -1766,8 +2003,17 @@ int posix_strerror_r(int err, char *buf, size_t len) {
   }
 }
 
+string StrError(int err) {
+  char buf[100];
+  int rc = posix_strerror_r(err, buf, sizeof(buf));
+  if ((rc < 0) || (buf[0] == '\000')) {
+    snprintf(buf, sizeof(buf), "Error number %d", err);
+  }
+  return buf;
+}
+
 LogMessageFatal::LogMessageFatal(const char* file, int line) :
-    LogMessage(file, line, FATAL) {}
+    LogMessage(file, line, GLOG_FATAL) {}
 
 LogMessageFatal::LogMessageFatal(const char* file, int line,
                                  const CheckOpString& result) :
@@ -1778,4 +2024,65 @@ LogMessageFatal::~LogMessageFatal() {
     LogMessage::Fail();
 }
 
+namespace base {
+
+CheckOpMessageBuilder::CheckOpMessageBuilder(const char *exprtext)
+    : stream_(new ostringstream) {
+  *stream_ << exprtext << " (";
+}
+
+CheckOpMessageBuilder::~CheckOpMessageBuilder() {
+  delete stream_;
+}
+
+ostream* CheckOpMessageBuilder::ForVar2() {
+  *stream_ << " vs. ";
+  return stream_;
+}
+
+string* CheckOpMessageBuilder::NewString() {
+  *stream_ << ")";
+  return new string(stream_->str());
+}
+
+}  // namespace base
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const char& v) {
+  if (v >= 32 && v <= 126) {
+    (*os) << "'" << v << "'";
+  } else {
+    (*os) << "char value " << (short)v;
+  }
+}
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const signed char& v) {
+  if (v >= 32 && v <= 126) {
+    (*os) << "'" << v << "'";
+  } else {
+    (*os) << "signed char value " << (short)v;
+  }
+}
+
+template <>
+void MakeCheckOpValueString(std::ostream* os, const unsigned char& v) {
+  if (v >= 32 && v <= 126) {
+    (*os) << "'" << v << "'";
+  } else {
+    (*os) << "unsigned char value " << (unsigned short)v;
+  }
+}
+
+void InitGoogleLogging(const char* argv0) {
+  glog_internal_namespace_::InitGoogleLoggingUtilities(argv0);
+}
+
+void ShutdownGoogleLogging() {
+  glog_internal_namespace_::ShutdownGoogleLoggingUtilities();
+  LogDestination::DeleteLogDestinations();
+  delete logging_directories_list;
+  logging_directories_list = NULL;
+}
+
 _END_GOOGLE_NAMESPACE_