Adds color output support for tmux terminals
[platform/upstream/glog.git] / src / logging.cc
index 06516fb..5543e3a 100644 (file)
@@ -1,23 +1,60 @@
+// Copyright (c) 1999, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 #define _GNU_SOURCE 1 // needed for O_NOFOLLOW and pread()/pwrite()
 
 #include "utilities.h"
 
+#include <algorithm>
 #include <assert.h>
-#include <pthread.h>
 #include <iomanip>
 #include <string>
-#include <unistd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>  // For _exit.
+#endif
 #include <climits>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/utsname.h>
+#ifdef HAVE_SYS_UTSNAME_H
+# include <sys/utsname.h>  // For uname.
+#endif
 #include <fcntl.h>
 #include <cstdio>
 #include <iostream>
 #include <stdarg.h>
 #include <stdlib.h>
-#include <pwd.h>
-#include <syslog.h>
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
 #include <vector>
 #include <errno.h>                   // for errno
 #include <sstream>
 #include "glog/raw_logging.h"
 #include "base/googleinit.h"
 
+#ifdef HAVE_STACKTRACE
+# include "stacktrace.h"
+#endif
+
 using std::string;
 using std::vector;
-using std::ostrstream;
 using std::setw;
+using std::setfill;
 using std::hex;
 using std::dec;
 using std::min;
 using std::ostream;
 using std::ostringstream;
-using std::strstream;
 
-DEFINE_bool(logtostderr, false,
-            "log messages go to stderr instead of logfiles");
-DEFINE_bool(alsologtostderr, false,
-            "log messages go to stderr in addition to logfiles");
+using std::FILE;
+using std::fwrite;
+using std::fclose;
+using std::fflush;
+using std::fprintf;
+using std::perror;
+
+#ifdef __QNX__
+using std::fdopen;
+#endif
+
+// There is no thread annotation support.
+#define EXCLUSIVE_LOCKS_REQUIRED(mu)
+
+static bool BoolFromEnv(const char *varname, bool defval) {
+  const char* const valstr = getenv(varname);
+  if (!valstr) {
+    return defval;
+  }
+  return memchr("tTyY1\0", valstr[0], 6) != NULL;
+}
+
+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
+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();
+}
+_END_GOOGLE_NAMESPACE_
+#endif
 
 // By default, errors (including fatal errors) get logged to stderr as
 // well as the file.
@@ -48,29 +123,29 @@ DEFINE_bool(alsologtostderr, false,
 // 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() {
@@ -86,23 +161,203 @@ 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_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_int32(max_log_size, 1800,
-             "approx. maximum log file size (in MB)");
+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_bool(stop_logging_if_full_disk, false,
-            "Stop attempting to log to disk if the disk is full.");
+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;
+  if (0 != uname(&buf)) {
+    // ensure null termination on failure
+    *buf.nodename = '\0';
+  }
+  *hostname = buf.nodename;
+#elif defined(OS_WINDOWS)
+  char buf[MAX_COMPUTERNAME_LENGTH + 1];
+  DWORD len = MAX_COMPUTERNAME_LENGTH + 1;
+  if (GetComputerNameA(buf, &len)) {
+    *hostname = buf;
+  } else {
+    hostname->clear();
+  }
+#else
+# warning There is no way to retrieve the host name.
+  *hostname = "(unknown)";
+#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
@@ -120,6 +375,9 @@ const char*const LogSeverityNames[NUM_SEVERITIES] = {
   "INFO", "WARNING", "ERROR", "FATAL"
 };
 
+// Has the user called SetExitOnDFatal(true)?
+static bool exit_on_dfatal = true;
+
 const char* GetLogSeverityName(LogSeverity severity) {
   return LogSeverityNames[severity];
 }
@@ -130,6 +388,8 @@ static bool SendEmailInternal(const char*dest, const char *subject,
 base::Logger::~Logger() {
 }
 
+namespace {
+
 // Encapsulates all file-system related state
 class LogFileObject : public base::Logger {
  public:
@@ -179,64 +439,10 @@ 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);
 };
 
-LogFileObject::LogFileObject(LogSeverity severity,
-                             const char* base_filename)
-  : base_filename_selected_(base_filename != NULL),
-    base_filename_((base_filename != NULL) ? base_filename : ""),
-    symlink_basename_(ProgramInvocationShortName()),
-    filename_extension_(),
-    file_(NULL),
-    severity_(severity),
-    bytes_since_flush_(0),
-    file_length_(0),
-    rollover_attempt_(kRolloverAttemptFrequency-1),
-    next_flush_time_(0) {
-  assert(severity >= 0);
-  assert(severity < NUM_SEVERITIES);
-}
-
-LogFileObject::~LogFileObject() {
-  MutexLock l(&lock_);
-  if (file_ != NULL) {
-    fclose(file_);
-    file_ = NULL;
-  }
-}
-
-void LogFileObject::SetBasename(const char* basename) {
-  MutexLock l(&lock_);
-  base_filename_selected_ = true;
-  if (base_filename_ != basename) {
-    // Get rid of old log file since we are changing names
-    if (file_ != NULL) {
-      fclose(file_);
-      file_ = NULL;
-      rollover_attempt_ = kRolloverAttemptFrequency-1;
-    }
-    base_filename_ = basename;
-  }
-}
-
-void LogFileObject::SetExtension(const char* ext) {
-  MutexLock l(&lock_);
-  if (filename_extension_ != ext) {
-    // Get rid of old log file since we are changing names
-    if (file_ != NULL) {
-      fclose(file_);
-      file_ = NULL;
-      rollover_attempt_ = kRolloverAttemptFrequency-1;
-    }
-    filename_extension_ = ext;
-  }
-}
-
-void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
-  MutexLock l(&lock_);
-  symlink_basename_ = symlink_basename;
-}
+}  // namespace
 
 class LogDestination {
  public:
@@ -266,8 +472,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() { }
 
@@ -314,6 +525,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_;
@@ -330,19 +542,18 @@ class LogDestination {
 // Errors do not get logged to email by default.
 LogSeverity LogDestination::email_logging_severity_ = 99999;
 
-string LogDestination::addresses_ = "";
-string LogDestination::hostname_ = "";
+string LogDestination::addresses_;
+string LogDestination::hostname_;
 
 vector<LogSink*>* LogDestination::sinks_ = NULL;
 Mutex LogDestination::sink_mutex_;
+bool LogDestination::terminal_supports_color_ = TerminalSupportsColor();
 
 /* static */
 const string& LogDestination::hostname() {
   if (hostname_.empty()) {
-    struct utsname buf;
-    if (0 == uname(&buf)) {
-      hostname_ = buf.nodename;
-    } else {
+    GetHostName(&hostname_);
+    if (hostname_.empty()) {
       hostname_ = "(unknown)";
     }
   }
@@ -355,22 +566,6 @@ LogDestination::LogDestination(LogSeverity severity,
     logger_(&fileobject_) {
 }
 
-void LogFileObject::Flush() {
-  MutexLock l(&lock_);
-  FlushUnlocked();
-}
-
-void LogFileObject::FlushUnlocked(){
-  if (file_ != NULL) {
-    fflush(file_);
-    bytes_since_flush_ = 0;
-  }
-  // Figure out when we are due for another flush.
-  const int64 next = (FLAGS_logbufsecs
-                      * static_cast<int64>(1000000));  // in usec
-  next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
-}
-
 inline void LogDestination::FlushLogFilesUnsafe(int min_severity) {
   // assume we have the log_mutex or we simply don't care
   // about it
@@ -473,6 +668,43 @@ 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.
@@ -482,7 +714,7 @@ static void WriteToStderr(const char* message, size_t len) {
 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());
@@ -503,7 +735,7 @@ inline void LogDestination::MaybeLogToEmail(LogSeverity severity,
       to += addresses_;
     }
     const string subject(string("[LOG] ") + LogSeverityNames[severity] + ": " +
-                         ProgramInvocationShortName());
+                         glog_internal_namespace_::ProgramInvocationShortName());
     string body(hostname());
     body += "\n\n";
     body.append(message, len);
@@ -531,12 +763,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,
@@ -562,20 +794,115 @@ inline void LogDestination::WaitForSinks(LogMessage::LogMessageData* data) {
       (*sinks_)[i]->WaitTillSent();
     }
   }
-  if (data->send_method_ == &LogMessage::SendToSinkAndLog &&
-      data->sink_ != NULL) {
+  const bool send_to_sink =
+      (data->send_method_ == &LogMessage::SendToSink) ||
+      (data->send_method_ == &LogMessage::SendToSinkAndLog);
+  if (send_to_sink && data->sink_ != NULL) {
     data->sink_->WaitTillSent();
   }
 }
 
-bool LogFileObject::CreateLogfile(const char* time_pid_string) {
+LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
+
+inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
+  assert(severity >=0 && severity < NUM_SEVERITIES);
+  if (!log_destinations_[severity]) {
+    log_destinations_[severity] = new LogDestination(severity, NULL);
+  }
+  return log_destinations_[severity];
+}
+
+void LogDestination::DeleteLogDestinations() {
+  for (int severity = 0; severity < NUM_SEVERITIES; ++severity) {
+    delete log_destinations_[severity];
+    log_destinations_[severity] = NULL;
+  }
+}
+
+namespace {
+
+LogFileObject::LogFileObject(LogSeverity severity,
+                             const char* base_filename)
+  : base_filename_selected_(base_filename != NULL),
+    base_filename_((base_filename != NULL) ? base_filename : ""),
+    symlink_basename_(glog_internal_namespace_::ProgramInvocationShortName()),
+    filename_extension_(),
+    file_(NULL),
+    severity_(severity),
+    bytes_since_flush_(0),
+    file_length_(0),
+    rollover_attempt_(kRolloverAttemptFrequency-1),
+    next_flush_time_(0) {
+  assert(severity >= 0);
+  assert(severity < NUM_SEVERITIES);
+}
+
+LogFileObject::~LogFileObject() {
+  MutexLock l(&lock_);
+  if (file_ != NULL) {
+    fclose(file_);
+    file_ = NULL;
+  }
+}
+
+void LogFileObject::SetBasename(const char* basename) {
+  MutexLock l(&lock_);
+  base_filename_selected_ = true;
+  if (base_filename_ != basename) {
+    // Get rid of old log file since we are changing names
+    if (file_ != NULL) {
+      fclose(file_);
+      file_ = NULL;
+      rollover_attempt_ = kRolloverAttemptFrequency-1;
+    }
+    base_filename_ = basename;
+  }
+}
+
+void LogFileObject::SetExtension(const char* ext) {
+  MutexLock l(&lock_);
+  if (filename_extension_ != ext) {
+    // Get rid of old log file since we are changing names
+    if (file_ != NULL) {
+      fclose(file_);
+      file_ = NULL;
+      rollover_attempt_ = kRolloverAttemptFrequency-1;
+    }
+    filename_extension_ = ext;
+  }
+}
+
+void LogFileObject::SetSymlinkBasename(const char* symlink_basename) {
+  MutexLock l(&lock_);
+  symlink_basename_ = symlink_basename;
+}
+
+void LogFileObject::Flush() {
+  MutexLock l(&lock_);
+  FlushUnlocked();
+}
+
+void LogFileObject::FlushUnlocked(){
+  if (file_ != NULL) {
+    fflush(file_);
+    bytes_since_flush_ = 0;
+  }
+  // Figure out when we are due for another flush.
+  const int64 next = (FLAGS_logbufsecs
+                      * static_cast<int64>(1000000));  // in usec
+  next_flush_time_ = CycleClock_Now() + UsecToCycles(next);
+}
+
+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);
   if (fd == -1) return false;
+#ifdef HAVE_FCNTL
   // Mark the file close-on-exec. We don't really care if this fails
   fcntl(fd, F_SETFD, FD_CLOEXEC);
+#endif
 
   file_ = fdopen(fd, "a");  // Make a FILE*.
   if (file_ == NULL) {  // Man, we're screwed!
@@ -599,18 +926,27 @@ 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.
     // 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
   }
 
   return true;  // Everything worked
@@ -627,8 +963,9 @@ void LogFileObject::Write(bool force_flush,
     return;
   }
 
-  if ((file_length_ >> 20) >= FLAGS_max_log_size) {
-    fclose(file_);
+  if (static_cast<int>(file_length_ >> 20) >= MaxLogSize() ||
+      PidHasChanged()) {
+    if (file_ != NULL) fclose(file_);
     file_ = NULL;
     file_length_ = bytes_since_flush_ = 0;
     rollover_attempt_ = kRolloverAttemptFrequency-1;
@@ -646,24 +983,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 {
@@ -678,11 +1015,10 @@ void LogFileObject::Write(bool force_flush,
       //
       // Where does the file get put?  Successively try the directories
       // "/tmp", and "."
-      string stripped_filename(ProgramInvocationShortName());  // in cmdlineflag
-      struct utsname buf;
-      if (0 != uname(&buf)) {
-        *buf.nodename = '\0';  // ensure null termination on failure
-      }
+      string stripped_filename(
+          glog_internal_namespace_::ProgramInvocationShortName());
+      string hostname;
+      GetHostName(&hostname);
 
       string uidname = MyUserName();
       // We should not call CHECK() here because this function can be
@@ -691,7 +1027,7 @@ void LogFileObject::Write(bool force_flush,
       // deadlock. Simply use a name like invalid-user.
       if (uidname.empty()) uidname = "invalid-user";
 
-      stripped_filename = stripped_filename+'.'+buf.nodename+'.'
+      stripped_filename = stripped_filename+'.'+hostname+'.'
                           +uidname+".log."
                           +LogSeverityNames[severity_]+'.';
       // We're going to (potentially) try to put logs in several different dirs
@@ -712,15 +1048,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 << '/'
@@ -732,9 +1067,12 @@ void LogFileObject::Write(bool force_flush,
                        << setw(2) << tm_time.tm_sec << '\n'
                        << "Running on machine: "
                        << LogDestination::hostname() << '\n'
-                       << '\0';
-    int header_len = strlen(file_header_string);
-    fwrite(file_header_string, 1, header_len, file_);
+                       << "Log line format: [IWEF]mmdd hh:mm:ss.uuuuuu "
+                       << "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;
   }
@@ -768,172 +1106,155 @@ void LogFileObject::Write(bool force_flush,
        (bytes_since_flush_ >= 1000000) ||
        (CycleClock_Now() >= next_flush_time_) ) {
     FlushUnlocked();
+#ifdef OS_LINUX
+    if (FLAGS_drop_log_memory) {
+      if (file_length_ >= logging::kPageSize) {
+        // don't evict the most recent page
+        uint32 len = file_length_ & ~(logging::kPageSize - 1);
+        posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED);
+      }
+    }
+#endif
   }
 }
 
-LogDestination* LogDestination::log_destinations_[NUM_SEVERITIES];
-
-inline LogDestination* LogDestination::log_destination(LogSeverity severity) {
-  assert(severity >=0 && severity < NUM_SEVERITIES);
-  if (!log_destinations_[severity]) {
-    log_destinations_[severity] = new LogDestination(severity, NULL);
-  }
-  return log_destinations_[severity];
-}
+}  // namespace
 
-// Get the part of filepath after the last path separator.
-// (Doesn't modify filepath, contrary to basename() in libgen.h.)
-static const char* const_basename(const char* filepath) {
-  const char* base = strrchr(filepath, '/');
-#ifdef OS_WINDOWS  // Look for either path separator in Windows
-  if (!base)
-    base = strrchr(filepath, '\\');
-#endif
-  return base ? (base+1) : filepath;
-}
 
+// Static log data space to avoid alloc failures in a LOG(FATAL)
 //
-// LogMessage's constructor starts each message with a string like:
-// I1018 160715 logging.cc:1153]
-// (1st letter of severity level, GMT month, date, & time;
-// thread id (if not 0x400); basename of file and line of the logging command)
-// We ignore thread id 0x400 because it seems to be the default for single-
-// threaded programs.
-
-// 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;
+// Since multiple threads may call LOG(FATAL), and we want to preserve
+// the data from the first call, we allocate two sets of space.  One
+// for exclusive use by the first thread, and one for shared use by
+// all other threads.
+static Mutex fatal_msg_lock;
+static CrashReason crash_reason;
+static bool fatal_msg_exclusive = true;
+static LogMessage::LogMessageData fatal_msg_data_exclusive;
+static LogMessage::LogMessageData fatal_msg_data_shared;
 
-// Need to reserve some space for FATAL messages because
-// we usually do LOG(FATAL) when we ran out of heap memory.
-// However, since LogMessage() also calls new[], in this case,
-// it will recusively call LOG(FATAL), which then call new[] ... etc.
-// Eventually, the program will run out of stack memory and no message
-// will get logged.   Note that we will not be protecting this buffer
-// with a lock because the chances are very small that there will
-// be a contention during LOG(FATAL) which can only happen at most
-// once per program.
-static char fatal_message_buffer[LogMessage::kMaxLogMessageLen+1];
-
-// Similarly we reserve space for a LogMessageData struct to be used
-// for FATAL messages.
-LogMessage::LogMessageData LogMessage::fatal_message_data_(0, FATAL, 0);
-
-LogMessage::LogMessageData::LogMessageData(int preserved_errno,
-                                           LogSeverity severity,
-                                           int ctr) :
-    // ORDER DEPENDENCY: buf_ comes before message_text_ comes before stream_
-    preserved_errno_(preserved_errno),
-    // Use static buffer for LOG(FATAL)
-    buf_((severity != FATAL) ? new char[kMaxLogMessageLen+1] : NULL),
-    message_text_((severity != FATAL) ? buf_ : fatal_message_buffer),
-    stream_(message_text_, kMaxLogMessageLen, ctr),
-    severity_(severity) {
-}
-
-LogMessage::LogMessageData::~LogMessageData() {
-  delete[] buf_;
-}
-
-LogMessage::LogMessageData* LogMessage::GetMessageData(int preserved_errno,
-                                                       LogSeverity severity,
-                                                       int ctr) {
-  if (severity != FATAL) {
-    return allocated_;
-  } else {
-    fatal_message_data_.preserved_errno_ = preserved_errno;
-    fatal_message_data_.stream_.set_ctr(ctr);
-    return &fatal_message_data_;
-  }
+LogMessage::LogMessageData::LogMessageData()
+  : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
 }
 
 LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
-                      int ctr, void (LogMessage::*send_method)()) :
-    allocated_((severity != FATAL) ?
-               new LogMessageData(errno, severity, ctr) : NULL),
-    data_(GetMessageData(errno, severity, ctr)) {
+                       int ctr, void (LogMessage::*send_method)())
+    : allocated_(NULL) {
   Init(file, line, severity, send_method);
+  data_->stream_.set_ctr(ctr);
 }
 
-LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
-    : allocated_(NULL),
-      data_(GetMessageData(errno, FATAL, 0)) {
-  Init(file, line, FATAL, &LogMessage::SendToLog);
+LogMessage::LogMessage(const char* file, int line,
+                       const CheckOpString& result)
+    : allocated_(NULL) {
+  Init(file, line, GLOG_FATAL, &LogMessage::SendToLog);
   stream() << "Check failed: " << (*result.str_) << " ";
 }
 
-LogMessage::LogMessage(const char* file, int line) :
-    allocated_(new LogMessageData(errno, INFO, 0)),
-    data_(GetMessageData(errno, INFO, 0)) {
-  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) :
-    allocated_((severity != FATAL) ?
-               new LogMessageData(errno, severity, 0) : NULL),
-    data_(GetMessageData(errno, severity, 0)) {
+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) :
-    allocated_((severity != FATAL) ?
-               new LogMessageData(errno, severity, 0) : NULL),
-    data_(GetMessageData(errno, severity, 0)) {
-  Init(file, line, severity, &LogMessage::SendToSinkAndLog);
+                       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) :
-    allocated_((severity != FATAL) ?
-               new LogMessageData(errno, severity, 0) : NULL),
-    data_(GetMessageData(errno, severity, 0)) {
+                       vector<string> *outvec)
+    : allocated_(NULL) {
   Init(file, line, severity, &LogMessage::SaveOrSendToLog);
   data_->outvec_ = outvec; // override Init()'s setting to NULL
 }
 
-void LogMessage::Init(const char* file, int line, LogSeverity severity,
+LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
+                       string *message)
+    : allocated_(NULL) {
+  Init(file, line, severity, &LogMessage::WriteToStringAndLog);
+  data_->message_ = message;  // override Init()'s setting to NULL
+}
+
+void LogMessage::Init(const char* file,
+                      int line,
+                      LogSeverity severity,
                       void (LogMessage::*send_method)()) {
+  allocated_ = NULL;
+  if (severity != GLOG_FATAL || !exit_on_dfatal) {
+    allocated_ = new LogMessageData();
+    data_ = allocated_;
+    data_->first_fatal_ = false;
+  } else {
+    MutexLock l(&fatal_msg_lock);
+    if (fatal_msg_exclusive) {
+      fatal_msg_exclusive = false;
+      data_ = &fatal_msg_data_exclusive;
+      data_->first_fatal_ = true;
+    } else {
+      data_ = &fatal_msg_data_shared;
+      data_->first_fatal_ = false;
+    }
+  }
+
+  stream().fill('0');
+  data_->preserved_errno_ = errno;
+  data_->severity_ = severity;
   data_->line_ = line;
   data_->send_method_ = send_method;
-
-  data_->outvec_ = NULL;
   data_->sink_ = NULL;
-  data_->timestamp_ = time(NULL);
+  data_->outvec_ = NULL;
+  WallTime now = WallTime_Now();
+  data_->timestamp_ = static_cast<time_t>(now);
   localtime_r(&data_->timestamp_, &data_->tm_time_);
-  RawLog__SetLastTime(data_->tm_time_);
+  int usecs = static_cast<int>((now - data_->timestamp_) * 1000000);
+  RawLog__SetLastTime(data_->tm_time_, usecs);
+
+  data_->num_chars_to_log_ = 0;
+  data_->num_chars_to_syslog_ = 0;
   data_->basename_ = const_basename(file);
   data_->fullname_ = file;
-  data_->stream_.fill('0');
+  data_->has_been_flushed_ = false;
 
-  // In some cases, we use logging like a print mechanism and
-  // the prefixes get in the way
+  // If specified, prepend a prefix to each line.  For example:
+  //    I1018 160715 f5d4fbb0 logging.cc:1153]
+  //    (log level, GMT month, date, time, thread_id, file basename, line)
+  // We exclude the thread_id for the default thread.
   if (FLAGS_log_prefix && (line != kNoLogPrefix)) {
-    if ( is_default_thread() ) {
-      stream() << LogSeverityNames[severity][0]
-               << setw(2) << 1+data_->tm_time_.tm_mon
-               << setw(2) << data_->tm_time_.tm_mday
-               << ' '
-               << setw(2) << data_->tm_time_.tm_hour
-               << setw(2) << data_->tm_time_.tm_min
-               << setw(2) << data_->tm_time_.tm_sec
-               << ' ' << data_->basename_ << ':' << data_->line_ << "] ";
-    } else {
-      stream() << LogSeverityNames[severity][0]
-               << setw(2) << 1+data_->tm_time_.tm_mon
-               << setw(2) << data_->tm_time_.tm_mday
-               << ' '
-               << setw(2) << data_->tm_time_.tm_hour
-               << setw(2) << data_->tm_time_.tm_min
-               << setw(2) << data_->tm_time_.tm_sec
-               << ' ' << setw(8) << std::hex << pthread_self() << std::dec
-               << ' ' << data_->basename_ << ':' << data_->line_ << "] ";
-    }
+    stream() << LogSeverityNames[severity][0]
+             << setw(2) << 1+data_->tm_time_.tm_mon
+             << setw(2) << data_->tm_time_.tm_mday
+             << ' '
+             << setw(2) << data_->tm_time_.tm_hour  << ':'
+             << setw(2) << data_->tm_time_.tm_min   << ':'
+             << setw(2) << data_->tm_time_.tm_sec   << "."
+             << setw(6) << usecs
+             << ' '
+             << setfill(' ') << setw(5)
+             << static_cast<unsigned int>(GetTID()) << setfill('0')
+             << ' '
+             << data_->basename_ << ':' << data_->line_ << "] ";
   }
-
   data_->num_prefix_chars_ = data_->stream_.pcount();
-  data_->has_been_flushed_ = false;
+
+  if (!FLAGS_log_backtrace_at.empty()) {
+    char fileline[128];
+    snprintf(fileline, sizeof(fileline), "%s:%d", data_->basename_, line);
+#ifdef HAVE_STACKTRACE
+    if (!strcmp(FLAGS_log_backtrace_at.c_str(), fileline)) {
+      string stacktrace;
+      DumpStackTraceToString(&stacktrace);
+      stream() << " (stacktrace:\n" << stacktrace << ") ";
+    }
+#endif
+  }
 }
 
 LogMessage::~LogMessage() {
@@ -941,6 +1262,14 @@ 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() {
@@ -953,7 +1282,7 @@ void LogMessage::Flush() {
 
   // Do we need to add a \n to the end of this message?
   bool append_newline =
-    (data_->message_text_[data_->num_chars_to_log_-1] != '\n');
+      (data_->message_text_[data_->num_chars_to_log_-1] != '\n');
   char original_final_char = '\0';
 
   // If we do need to add a \n, we'll do it by violating the memory of the
@@ -995,13 +1324,9 @@ void LogMessage::Flush() {
   data_->has_been_flushed_ = true;
 }
 
-// Copy of FATAL log message so that we can print it out again after
-// all the stack traces.
-// We cannot simply use fatal_message_buffer, because two or more FATAL log
-// messages may happen in a row. This is a real possibility given that
-// FATAL log messages are often associated with corrupted process state.
-// In this case, we still want to reprint the first FATAL log message, so
-// we need to save away the first message in a separate buffer.
+// 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_data_exclusive.
 static time_t fatal_time;
 static char fatal_message[256];
 
@@ -1009,15 +1334,15 @@ 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);
   }
 }
 
 // L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SendToLog() {
+void LogMessage::SendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
   static bool already_warned_before_initgoogle = false;
 
   log_mutex.AssertHeld();
@@ -1038,7 +1363,8 @@ void LogMessage::SendToLog() {
   // 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_,
@@ -1070,13 +1396,20 @@ void LogMessage::SendToLog() {
   // 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) {
-    // save away the fatal message so we can print it again later
-    const int copy = min<int>(data_->num_chars_to_log_,
-                              sizeof(fatal_message)-1);
-    memcpy(fatal_message, data_->message_text_, copy);
-    fatal_message[copy] = '\0';
-    fatal_time = data_->timestamp_;
+  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.
+      RecordCrashReason(&crash_reason);
+      SetCrashReason(&crash_reason);
+
+      // Store shortened fatal message for other logs and GWQ status
+      const int copy = min<int>(data_->num_chars_to_log_,
+                                sizeof(fatal_message)-1);
+      memcpy(fatal_message, data_->message_text_, copy);
+      fatal_message[copy] = '\0';
+      fatal_time = data_->timestamp_;
+    }
 
     if (!FLAGS_logtostderr) {
       for (int i = 0; i < NUM_SEVERITIES; ++i) {
@@ -1084,7 +1417,7 @@ void LogMessage::SendToLog() {
           LogDestination::log_destinations_[i]->logger_->Write(true, 0, "", 0);
       }
     }
-    
+
     // release the lock that our caller (directly or indirectly)
     // LogMessage::~LogMessage() grabbed so that signal handlers
     // can use the logging facility. Alternately, we could add
@@ -1093,28 +1426,53 @@ void LogMessage::SendToLog() {
     log_mutex.Unlock();
     LogDestination::WaitForSinks(data_);
 
+    const char* message = "*** Check failure stack trace: ***\n";
+    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_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);
+#else
+  reason->depth = 0;
+#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 COMPILER_MSVC
+#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__
-void (*g_logging_fail_func)() __attribute__((noreturn)) = &logging_fail;
-#else
-void (*g_logging_fail_func)() = &logging_fail;
-#endif
+typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
+
+GOOGLE_GLOG_DLL_DECL
+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() {
@@ -1122,7 +1480,7 @@ void LogMessage::Fail() {
 }
 
 // L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SendToSinkAndLog() {
+void LogMessage::SendToSink() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
   if (data_->sink_ != NULL) {
     RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
                data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
@@ -1132,11 +1490,16 @@ void LogMessage::SendToSinkAndLog() {
                        (data_->num_chars_to_log_ -
                         data_->num_prefix_chars_ - 1));
   }
+}
+
+// L >= log_mutex (callers must hold the log_mutex).
+void LogMessage::SendToSinkAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+  SendToSink();
   SendToLog();
 }
 
 // L >= log_mutex (callers must hold the log_mutex).
-void LogMessage::SaveOrSendToLog() {
+void LogMessage::SaveOrSendToLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
   if (data_->outvec_ != NULL) {
     RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
                data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
@@ -1149,12 +1512,26 @@ void LogMessage::SaveOrSendToLog() {
   }
 }
 
+void LogMessage::WriteToStringAndLog() EXCLUSIVE_LOCKS_REQUIRED(log_mutex) {
+  if (data_->message_ != NULL) {
+    RAW_DCHECK(data_->num_chars_to_log_ > 0 &&
+               data_->message_text_[data_->num_chars_to_log_-1] == '\n', "");
+    // Omit prefix of message and trailing newline when writing to message_.
+    const char *start = data_->message_text_ + data_->num_prefix_chars_;
+    int len = data_->num_chars_to_log_ - data_->num_prefix_chars_ - 1;
+    data_->message_->assign(start, len);
+  }
+  SendToLog();
+}
+
 // L >= log_mutex (callers must hold the log_mutex).
 void LogMessage::SendToSyslogAndLog() {
+#ifdef HAVE_SYSLOG_H
   // Before any calls to syslog(), make a single call to openlog()
   static bool openlog_already_called = false;
   if (!openlog_already_called) {
-    openlog(ProgramInvocationShortName(), LOG_CONS | LOG_NDELAY | LOG_PID,
+    openlog(glog_internal_namespace_::ProgramInvocationShortName(),
+            LOG_CONS | LOG_NDELAY | LOG_PID,
             LOG_USER);
     openlog_already_called = true;
   }
@@ -1165,6 +1542,9 @@ void LogMessage::SendToSyslogAndLog() {
          int(data_->num_chars_to_syslog_),
          data_->message_text_ + data_->num_prefix_chars_);
   SendToLog();
+#else
+  LOG(ERROR) << "No syslog support: message=" << data_->message_text_;
+#endif
 }
 
 base::Logger* base::GetLogger(LogSeverity severity) {
@@ -1186,8 +1566,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;
 }
@@ -1201,9 +1586,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) {
@@ -1235,26 +1619,24 @@ string LogSink::ToString(LogSeverity severity, const char* file, int line,
   ostringstream stream(string(message, message_len));
   stream.fill('0');
 
-  if ( is_default_thread() ) {
-    stream << LogSeverityNames[severity][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
-           << ' ' << file << ':' << line << "] ";
-  } else {
-    stream << LogSeverityNames[severity][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
-           << ' ' << setw(8) << std::hex << pthread_self() << std::dec
-           << ' ' << file << ':' << line << "] ";
-  }
+  // FIXME(jrvb): Updating this to use the correct value for usecs
+  // requires changing the signature for both this method and
+  // LogSink::send().  This change needs to be done in a separate CL
+  // so subclasses of LogSink can be updated at the same time.
+  int usecs = 0;
+
+  stream << LogSeverityNames[severity][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 << '.'
+         << setw(6) << usecs
+         << ' '
+         << setfill(' ') << setw(5) << GetTID() << setfill('0')
+         << ' '
+         << file << ':' << line << "] ";
 
   stream << string(message, message_len);
   return stream.str();
@@ -1284,6 +1666,32 @@ void LogToStderr() {
   LogDestination::LogToStderr();
 }
 
+namespace base {
+namespace internal {
+
+bool GetExitOnDFatal() {
+  MutexLock l(&log_mutex);
+  return exit_on_dfatal;
+}
+
+// Determines whether we exit the program for a LOG(DFATAL) message in
+// debug mode.  It does this by skipping the call to Fail/FailQuietly.
+// This is intended for testing only.
+//
+// This can have some effects on LOG(FATAL) as well.  Failure messages
+// are always allocated (rather than sharing a buffer), the crash
+// reason is not recorded, the "gwq" status message is not updated,
+// and the stack trace is not recorded.  The LOG(FATAL) *will* still
+// exit the program.  Since this function is used only in testing,
+// these differences are acceptable.
+void SetExitOnDFatal(bool value) {
+  MutexLock l(&log_mutex);
+  exit_on_dfatal = value;
+}
+
+}  // namespace internal
+}  // namespace base
+
 // use_logging controls whether the logging functions LOG/VLOG are used
 // to log errors.  It should be set to false when the caller holds the
 // log_mutex.
@@ -1298,8 +1706,8 @@ static bool SendEmailInternal(const char*dest, const char *subject,
               subject, body, dest);
     }
 
-    string cmd(FLAGS_logmailer);
-    cmd = cmd + " -s\"" + string(subject) + "\" " + string(dest);
+    string cmd =
+        FLAGS_logmailer + " -s\"" + subject + "\" " + dest;
     FILE* pipe = popen(cmd.c_str(), "w");
     if (pipe != NULL) {
       // Add the body if we have one
@@ -1308,13 +1716,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;
@@ -1333,7 +1739,7 @@ bool SendEmail(const char*dest, const char *subject, const char*body){
   return SendEmailInternal(dest, subject, body, true);
 }
 
-void GetTempDirectories(vector<string>* list) {
+static void GetTempDirectories(vector<string>* list) {
   list->clear();
 #ifdef OS_WINDOWS
   // On windows we'll try to find a directory in this order:
@@ -1361,7 +1767,7 @@ void GetTempDirectories(vector<string>* list) {
     "/tmp",
   };
 
-  for (int i = 0; i < sizeof(candidates) / sizeof(*candidates); i++) {
+  for (size_t i = 0; i < ARRAYSIZE(candidates); i++) {
     const char *d = candidates[i];
     if (!d) continue;  // Empty env var
 
@@ -1429,15 +1835,18 @@ void GetExistingTempDirectories(vector<string>* list) {
 }
 
 void TruncateLogFile(const char *path, int64 limit, int64 keep) {
-
+#ifdef HAVE_UNISTD_H
   struct stat statbuf;
   const int kCopyBlockSize = 8 << 10;
   char copybuf[kCopyBlockSize];
   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) {
@@ -1448,19 +1857,19 @@ 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;
     }
     return;
   }
-  
+
   if (fstat(fd, &statbuf) == -1) {
-    PLOG(ERROR) << "Unable to fstat()"; 
-    goto out_close_fd; 
+    PLOG(ERROR) << "Unable to fstat()";
+    goto out_close_fd;
   }
 
   // See if the path refers to a regular file bigger than the
@@ -1471,9 +1880,9 @@ void TruncateLogFile(const char *path, int64 limit, int64 keep) {
 
   // This log file is too large - we need to truncate it
   LOG(INFO) << "Truncating " << path << " to " << keep << " bytes";
-  
+
   // Copy the last "keep" bytes of the file to the beginning of the file
-  read_offset = statbuf.st_size - keep; 
+  read_offset = statbuf.st_size - keep;
   write_offset = 0;
   int bytesin, bytesout;
   while ((bytesin = pread(fd, copybuf, sizeof(copybuf), read_offset)) > 0) {
@@ -1488,7 +1897,7 @@ void TruncateLogFile(const char *path, int64 limit, int64 keep) {
     write_offset += bytesout;
   }
   if (bytesin == -1) PLOG(ERROR) << "Unable to read from " << path;
-  
+
   // Truncate the remainder of the file. If someone else writes to the
   // end of the file after our last read() above, we lose their latest
   // data. Too bad ...
@@ -1498,28 +1907,36 @@ void TruncateLogFile(const char *path, int64 limit, int64 keep) {
 
  out_close_fd:
   close(fd);
-
+#else
+  LOG(ERROR) << "No log truncation support.";
+#endif
 }
 
 void TruncateStdoutStderr() {
-  int64 limit = FLAGS_max_log_size << 20;
+#ifdef HAVE_UNISTD_H
+  int64 limit = MaxLogSize() << 20;
   int64 keep = 1 << 20;
   TruncateLogFile("/proc/self/fd/1", limit, keep);
   TruncateLogFile("/proc/self/fd/2", limit, keep);
+#else
+  LOG(ERROR) << "No log truncation support.";
+#endif
 }
 
 
 // Helper functions for string comparisons.
-#define DEFINE_CHECK_STROP_IMPL(name, func, expected) \
-  string* Check##func##expected##Impl(const char* s1, const char* s2, \
-                                      const char* names) { \
-    bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2)); \
-    if (equal == expected) return NULL; \
-    else { \
-      strstream ss; \
+#define DEFINE_CHECK_STROP_IMPL(name, func, expected)                   \
+  string* Check##func##expected##Impl(const char* s1, const char* s2,   \
+                                      const char* names) {              \
+    bool equal = s1 == s2 || (s1 && s2 && !func(s1, s2));               \
+    if (equal == expected) return NULL;                                 \
+    else {                                                              \
+      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)
 DEFINE_CHECK_STROP_IMPL(CHECK_STRNE, strcmp, false)
@@ -1565,8 +1982,8 @@ int posix_strerror_r(int err, char *buf, size_t len) {
       return 0;
     } else {
       buf[0] = '\000';
-#if defined(OS_MACOSX) || defined(OS_FREEBSD)
-      if (reinterpret_cast<int>(rc) < sys_nerr) {
+#if defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_OPENBSD)
+      if (reinterpret_cast<intptr_t>(rc) < sys_nerr) {
         // This means an error on MacOSX or FreeBSD.
         return -1;
       }
@@ -1577,8 +1994,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) :
@@ -1589,4 +2015,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_