X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Flogging.cc;h=73c3f403f3923da6c4bfebcdfede33169e0ffa07;hb=028d37889a1e80e8a07da1b8945ac706259e5fd8;hp=b7c2f4cb944626ce276e5925529bcc04b9a0452c;hpb=85e5c6edad157898a4a728392b8edd1d3361257f;p=platform%2Fupstream%2Fglog.git diff --git a/src/logging.cc b/src/logging.cc index b7c2f4c..73c3f40 100644 --- a/src/logging.cc +++ b/src/logging.cc @@ -88,6 +88,10 @@ using std::perror; using std::fdopen; #endif +#ifdef _WIN32 +#define fdopen _fdopen +#endif + // There is no thread annotation support. #define EXCLUSIVE_LOCKS_REQUIRED(mu) @@ -110,11 +114,6 @@ 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 @@ -434,6 +433,7 @@ class LogFileObject : public base::Logger { FILE* file_; LogSeverity severity_; uint32 bytes_since_flush_; + uint32 dropped_mem_length_; uint32 file_length_; unsigned int rollover_attempt_; int64 next_flush_time_; // cycle count at which to flush log @@ -572,7 +572,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. @@ -821,6 +821,7 @@ void LogDestination::DeleteLogDestinations() { } MutexLock l(&sink_mutex_); delete sinks_; + sinks_ = NULL; } namespace { @@ -834,6 +835,7 @@ LogFileObject::LogFileObject(LogSeverity severity, file_(NULL), severity_(severity), bytes_since_flush_(0), + dropped_mem_length_(0), file_length_(0), rollover_attempt_(kRolloverAttemptFrequency-1), next_flush_time_(0) { @@ -971,7 +973,7 @@ void LogFileObject::Write(bool force_flush, PidHasChanged()) { if (file_ != NULL) fclose(file_); file_ = NULL; - file_length_ = bytes_since_flush_ = 0; + file_length_ = bytes_since_flush_ = dropped_mem_length_ = 0; rollover_attempt_ = kRolloverAttemptFrequency-1; } @@ -1111,11 +1113,17 @@ void LogFileObject::Write(bool force_flush, (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); + // Only consider files >= 3MiB + if (FLAGS_drop_log_memory && file_length_ >= (3 << 20)) { + // Don't evict the most recent 1-2MiB so as not to impact a tailer + // of the log file and to avoid page rounding issue on linux < 4.7 + uint32 total_drop_length = (file_length_ & ~((1 << 20) - 1)) - (1 << 20); + uint32 this_drop_length = total_drop_length - dropped_mem_length_; + if (this_drop_length >= (2 << 20)) { + // Only advise when >= 2MiB to drop + posix_fadvise(fileno(file_), dropped_mem_length_, this_drop_length, + POSIX_FADV_DONTNEED); + dropped_mem_length_ = total_drop_length; } } #endif @@ -1137,6 +1145,14 @@ static bool fatal_msg_exclusive = true; static LogMessage::LogMessageData fatal_msg_data_exclusive; static LogMessage::LogMessageData fatal_msg_data_shared; +#ifdef GLOG_THREAD_LOCAL_STORAGE +// Static thread-local log data space to use, because typically at most one +// LogMessageData object exists (in this case glog makes zero heap memory +// allocations). +static GLOG_THREAD_LOCAL_STORAGE bool thread_data_available = true; +static GLOG_THREAD_LOCAL_STORAGE char thread_msg_data[sizeof(LogMessage::LogMessageData)]; +#endif // defined(GLOG_THREAD_LOCAL_STORAGE) + LogMessage::LogMessageData::LogMessageData() : stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) { } @@ -1193,8 +1209,19 @@ void LogMessage::Init(const char* file, void (LogMessage::*send_method)()) { allocated_ = NULL; if (severity != GLOG_FATAL || !exit_on_dfatal) { +#ifdef GLOG_THREAD_LOCAL_STORAGE + // No need for locking, because this is thread local. + if (thread_data_available) { + thread_data_available = false; + data_ = new (&thread_msg_data) LogMessageData; + } else { + allocated_ = new LogMessageData(); + data_ = allocated_; + } +#else // !defined(GLOG_THREAD_LOCAL_STORAGE) allocated_ = new LogMessageData(); data_ = allocated_; +#endif // defined(GLOG_THREAD_LOCAL_STORAGE) data_->first_fatal_ = false; } else { MutexLock l(&fatal_msg_lock); @@ -1263,7 +1290,17 @@ void LogMessage::Init(const char* file, LogMessage::~LogMessage() { Flush(); +#ifdef GLOG_THREAD_LOCAL_STORAGE + if (data_ == static_cast(thread_msg_data)) { + data_->~LogMessageData(); + thread_data_available = true; + } + else { + delete allocated_; + } +#else // !defined(GLOG_THREAD_LOCAL_STORAGE) delete allocated_; +#endif // defined(GLOG_THREAD_LOCAL_STORAGE) } int LogMessage::preserved_errno() const { @@ -1458,16 +1495,13 @@ void LogMessage::RecordCrashReason( # define ATTRIBUTE_NORETURN #endif +#if defined(OS_WINDOWS) +__declspec(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 - __debugbreak(); -#else abort(); -#endif } typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN; @@ -1696,6 +1730,42 @@ void SetExitOnDFatal(bool value) { } // namespace internal } // namespace base +// Shell-escaping as we need to shell out ot /bin/mail. +static const char kDontNeedShellEscapeChars[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+-_.=/:,@"; + +static string ShellEscape(const string& src) { + string result; + if (!src.empty() && // empty string needs quotes + src.find_first_not_of(kDontNeedShellEscapeChars) == string::npos) { + // only contains chars that don't need quotes; it's fine + result.assign(src); + } else if (src.find_first_of('\'') == string::npos) { + // no single quotes; just wrap it in single quotes + result.assign("'"); + result.append(src); + result.append("'"); + } else { + // needs double quote escaping + result.assign("\""); + for (size_t i = 0; i < src.size(); ++i) { + switch (src[i]) { + case '\\': + case '$': + case '"': + case '`': + result.append("\\"); + } + result.append(src, i, 1); + } + result.append("\""); + } + return result; +} + + // 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. @@ -1711,7 +1781,10 @@ static bool SendEmailInternal(const char*dest, const char *subject, } string cmd = - FLAGS_logmailer + " -s\"" + subject + "\" " + dest; + FLAGS_logmailer + " -s" + + ShellEscape(subject) + " " + ShellEscape(dest); + VLOG(4) << "Mailing command: " << cmd; + FILE* pipe = popen(cmd.c_str(), "w"); if (pipe != NULL) { // Add the body if we have one