1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/logging.h" 6 7 #include <sys/syscall.h> 8 #include <time.h> 9 #include <errno.h> 10 #include <pthread.h> 11 #include <stdio.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <sys/stat.h> 15 #include <unistd.h> 16 17 #include <algorithm> 18 #include <cstring> 19 #include <ctime> 20 #include <iomanip> 21 #include <ostream> 22 #include <string> 23 24 #include "base/posix/eintr_wrapper.h" 25 #include "base/strings/string_piece.h" 26 #include "base/strings/string_util.h" 27 #include "base/strings/stringprintf.h" 28 #include "base/strings/utf_string_conversion_utils.h" 29 30 namespace logging { 31 32 namespace { 33 34 const char* const log_severity_names[LOG_NUM_SEVERITIES] = { 35 "INFO", "WARNING", "ERROR", "FATAL" }; 36 37 const char* log_severity_name(int severity) { 38 if (severity >= 0 && severity < LOG_NUM_SEVERITIES) 39 return log_severity_names[severity]; 40 return "UNKNOWN"; 41 } 42 43 int g_min_log_level = 0; 44 45 LoggingDestination g_logging_destination = LOG_DEFAULT; 46 47 // For LOG_ERROR and above, always print to stderr. 48 const int kAlwaysPrintErrorLevel = LOG_ERROR; 49 50 // What should be prepended to each message? 51 bool g_log_timestamp = true; 52 53 // Should we pop up fatal debug messages in a dialog? 54 bool show_error_dialogs = false; 55 56 // An assert handler override specified by the client to be called instead of 57 // the debug message dialog and process termination. 58 LogAssertHandlerFunction log_assert_handler = nullptr; 59 // A log message handler that gets notified of every log message we process. 60 LogMessageHandlerFunction log_message_handler = nullptr; 61 62 // Helper functions to wrap platform differences. 63 64 } // namespace 65 66 LoggingSettings::LoggingSettings() 67 : logging_dest(LOG_DEFAULT) {} 68 69 bool BaseInitLoggingImpl(const LoggingSettings& settings) { 70 g_logging_destination = settings.logging_dest; 71 72 return true; 73 } 74 75 void SetMinLogLevel(int level) { 76 g_min_log_level = std::min(LOG_FATAL, level); 77 } 78 79 int GetMinLogLevel() { 80 return g_min_log_level; 81 } 82 83 bool ShouldCreateLogMessage(int severity) { 84 if (severity < g_min_log_level) 85 return false; 86 87 // Return true here unless we know ~LogMessage won't do anything. Note that 88 // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even 89 // when g_logging_destination is LOG_NONE. 90 return g_logging_destination != LOG_NONE || log_message_handler || 91 severity >= kAlwaysPrintErrorLevel; 92 } 93 94 int GetVlogVerbosity() { 95 return std::max(-1, LOG_INFO - GetMinLogLevel()); 96 } 97 98 void SetLogItems(bool enable_process_id, bool enable_thread_id, 99 bool enable_timestamp, bool enable_tickcount) { 100 g_log_timestamp = enable_timestamp; 101 } 102 103 void SetShowErrorDialogs(bool enable_dialogs) { 104 show_error_dialogs = enable_dialogs; 105 } 106 107 void SetLogAssertHandler(LogAssertHandlerFunction handler) { 108 log_assert_handler = handler; 109 } 110 111 void SetLogMessageHandler(LogMessageHandlerFunction handler) { 112 log_message_handler = handler; 113 } 114 115 LogMessageHandlerFunction GetLogMessageHandler() { 116 return log_message_handler; 117 } 118 119 // Explicit instantiations for commonly used comparisons. 120 template std::string* MakeCheckOpString<int, int>( 121 const int&, const int&, const char* names); 122 template std::string* MakeCheckOpString<unsigned long, unsigned long>( 123 const unsigned long&, const unsigned long&, const char* names); 124 template std::string* MakeCheckOpString<unsigned long, unsigned int>( 125 const unsigned long&, const unsigned int&, const char* names); 126 template std::string* MakeCheckOpString<unsigned int, unsigned long>( 127 const unsigned int&, const unsigned long&, const char* names); 128 template std::string* MakeCheckOpString<std::string, std::string>( 129 const std::string&, const std::string&, const char* name); 130 131 LogMessage::LogMessage(const char* file, int line, LogSeverity severity) 132 : severity_(severity), file_(file), line_(line) { 133 Init(file, line); 134 } 135 136 LogMessage::LogMessage(const char* file, int line, const char* condition) 137 : severity_(LOG_FATAL), file_(file), line_(line) { 138 Init(file, line); 139 stream_ << "Check failed: " << condition << ". "; 140 } 141 142 LogMessage::LogMessage(const char* file, int line, std::string* result) 143 : severity_(LOG_FATAL), file_(file), line_(line) { 144 Init(file, line); 145 stream_ << "Check failed: " << *result; 146 delete result; 147 } 148 149 LogMessage::LogMessage(const char* file, int line, LogSeverity severity, 150 std::string* result) 151 : severity_(severity), file_(file), line_(line) { 152 Init(file, line); 153 stream_ << "Check failed: " << *result; 154 delete result; 155 } 156 157 LogMessage::~LogMessage() { 158 stream_ << std::endl; 159 std::string str_newline(stream_.str()); 160 161 // Give any log message handler first dibs on the message. 162 if (log_message_handler && 163 log_message_handler(severity_, file_, line_, 164 message_start_, str_newline)) { 165 // The handler took care of it, no further processing. 166 return; 167 } 168 169 if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) { 170 ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); 171 fflush(stderr); 172 } else if (severity_ >= kAlwaysPrintErrorLevel) { 173 // When we're only outputting to a log file, above a certain log level, we 174 // should still output to stderr so that we can better detect and diagnose 175 // problems with unit tests, especially on the buildbots. 176 ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); 177 fflush(stderr); 178 } 179 180 if (severity_ == LOG_FATAL) { 181 // Ensure the first characters of the string are on the stack so they 182 // are contained in minidumps for diagnostic purposes. 183 char str_stack[1024]; 184 str_newline.copy(str_stack, arraysize(str_stack)); 185 186 if (log_assert_handler) { 187 // Make a copy of the string for the handler out of paranoia. 188 log_assert_handler(std::string(stream_.str())); 189 } else { 190 // Crash the process to generate a dump. 191 abort(); 192 } 193 } 194 } 195 196 // writes the common header info to the stream 197 void LogMessage::Init(const char* file, int line) { 198 base::StringPiece filename(file); 199 size_t last_slash_pos = filename.find_last_of("\\/"); 200 if (last_slash_pos != base::StringPiece::npos) 201 filename.remove_prefix(last_slash_pos + 1); 202 203 // TODO(darin): It might be nice if the columns were fixed width. 204 205 stream_ << '['; 206 if (g_log_timestamp) { 207 time_t t = time(nullptr); 208 struct tm local_time; 209 memset(&local_time, 0, sizeof(local_time)); 210 #ifdef _MSC_VER 211 localtime_s(&local_time, &t); 212 #else 213 localtime_r(&t, &local_time); 214 #endif 215 struct tm* tm_time = &local_time; 216 stream_ << std::setfill('0') 217 << std::setw(2) << 1 + tm_time->tm_mon 218 << std::setw(2) << tm_time->tm_mday 219 << '/' 220 << std::setw(2) << tm_time->tm_hour 221 << std::setw(2) << tm_time->tm_min 222 << std::setw(2) << tm_time->tm_sec 223 << ':'; 224 } 225 if (severity_ >= 0) 226 stream_ << log_severity_name(severity_); 227 else 228 stream_ << "VERBOSE" << -severity_; 229 230 stream_ << ":" << filename << "(" << line << ")] "; 231 232 message_start_ = stream_.str().length(); 233 } 234 235 void RawLog(int level, const char* message) { 236 if (level >= g_min_log_level) { 237 size_t bytes_written = 0; 238 const size_t message_len = strlen(message); 239 int rv; 240 while (bytes_written < message_len) { 241 rv = HANDLE_EINTR( 242 write(STDERR_FILENO, message + bytes_written, 243 message_len - bytes_written)); 244 if (rv < 0) { 245 // Give up, nothing we can do now. 246 break; 247 } 248 bytes_written += rv; 249 } 250 251 if (message_len > 0 && message[message_len - 1] != '\n') { 252 do { 253 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); 254 if (rv < 0) { 255 // Give up, nothing we can do now. 256 break; 257 } 258 } while (rv != 1); 259 } 260 } 261 262 if (level == LOG_FATAL) 263 abort(); 264 } 265 266 // This was defined at the beginning of this file. 267 #undef write 268 269 void LogErrorNotReached(const char* file, int line) { 270 LogMessage(file, line, LOG_ERROR).stream() 271 << "NOTREACHED() hit."; 272 } 273 274 } // namespace logging 275