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 <limits.h> 8#include <stdint.h> 9 10#include <iterator> 11#include <thread> 12 13#include "util/build_config.h" 14 15#if defined(OS_WIN) 16#include <io.h> 17#include <windows.h> 18// Windows warns on using write(). It prefers _write(). 19#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count)) 20// Windows doesn't define STDERR_FILENO. Define it here. 21#define STDERR_FILENO 2 22 23#elif defined(OS_POSIX) || defined(OS_FUCHSIA) 24#include <sys/time.h> 25#include <time.h> 26#endif 27 28#if defined(OS_POSIX) || defined(OS_FUCHSIA) 29#include <errno.h> 30#include <pthread.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#include <sys/stat.h> 35#include <unistd.h> 36#if !defined(OS_ZOS) 37#include <paths.h> 38#endif 39#endif 40 41#include <algorithm> 42#include <cstring> 43#include <ctime> 44#include <iomanip> 45#include <ostream> 46#include <string> 47#include <string_view> 48#include <utility> 49 50#include "base/posix/eintr_wrapper.h" 51#include "base/strings/string_util.h" 52#include "base/strings/stringprintf.h" 53#include "base/strings/utf_string_conversions.h" 54 55#if defined(OS_POSIX) || defined(OS_FUCHSIA) 56#include "base/posix/safe_strerror.h" 57#endif 58 59namespace logging { 60 61namespace { 62 63const char* const log_severity_names[] = {"INFO", "WARNING", "ERROR", "FATAL"}; 64static_assert(LOG_NUM_SEVERITIES == std::size(log_severity_names), 65 "Incorrect number of log_severity_names"); 66 67const char* log_severity_name(int severity) { 68 if (severity >= 0 && severity < LOG_NUM_SEVERITIES) 69 return log_severity_names[severity]; 70 return "UNKNOWN"; 71} 72 73int g_min_log_level = 0; 74 75// For LOG_ERROR and above, always print to stderr. 76const int kAlwaysPrintErrorLevel = LOG_ERROR; 77 78} // namespace 79 80#if defined(DCHECK_IS_CONFIGURABLE) 81// In DCHECK-enabled Chrome builds, allow the meaning of LOG_DCHECK to be 82// determined at run-time. We default it to INFO, to avoid it triggering 83// crashes before the run-time has explicitly chosen the behaviour. 84logging::LogSeverity LOG_DCHECK = LOG_INFO; 85#endif // DCHECK_IS_CONFIGURABLE 86 87// This is never instantiated, it's just used for EAT_STREAM_PARAMETERS to have 88// an object of the correct type on the LHS of the unused part of the ternary 89// operator. 90std::ostream* g_swallow_stream; 91 92void SetMinLogLevel(int level) { 93 g_min_log_level = std::min(LOG_FATAL, level); 94} 95 96int GetMinLogLevel() { 97 return g_min_log_level; 98} 99 100bool ShouldCreateLogMessage(int severity) { 101 if (severity < g_min_log_level) 102 return false; 103 104 // Return true here unless we know ~LogMessage won't do anything. Note that 105 // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even 106 // when g_logging_destination is LOG_NONE. 107 return severity >= kAlwaysPrintErrorLevel; 108} 109 110// Explicit instantiations for commonly used comparisons. 111template std::string* MakeCheckOpString<int, int>(const int&, 112 const int&, 113 const char* names); 114template std::string* MakeCheckOpString<unsigned long, unsigned long>( 115 const unsigned long&, 116 const unsigned long&, 117 const char* names); 118template std::string* MakeCheckOpString<unsigned long, unsigned int>( 119 const unsigned long&, 120 const unsigned int&, 121 const char* names); 122template std::string* MakeCheckOpString<unsigned int, unsigned long>( 123 const unsigned int&, 124 const unsigned long&, 125 const char* names); 126template std::string* MakeCheckOpString<std::string, std::string>( 127 const std::string&, 128 const std::string&, 129 const char* name); 130 131void MakeCheckOpValueString(std::ostream* os, std::nullptr_t p) { 132 (*os) << "nullptr"; 133} 134 135#if defined(OS_WIN) 136LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {} 137 138LogMessage::SaveLastError::~SaveLastError() { 139 ::SetLastError(last_error_); 140} 141#endif // defined(OS_WIN) 142 143LogMessage::LogMessage(const char* file, int line, LogSeverity severity) 144 : severity_(severity) { 145 Init(file, line); 146} 147 148LogMessage::LogMessage(const char* file, int line, const char* condition) 149 : severity_(LOG_FATAL) { 150 Init(file, line); 151 stream_ << "Check failed: " << condition << ". "; 152} 153 154LogMessage::LogMessage(const char* file, int line, std::string* result) 155 : severity_(LOG_FATAL) { 156 Init(file, line); 157 stream_ << "Check failed: " << *result; 158 delete result; 159} 160 161LogMessage::LogMessage(const char* file, 162 int line, 163 LogSeverity severity, 164 std::string* result) 165 : severity_(severity) { 166 Init(file, line); 167 stream_ << "Check failed: " << *result; 168 delete result; 169} 170 171LogMessage::~LogMessage() { 172 if (severity_ == LOG_FATAL) { 173 stream_ << std::endl; // Newline to separate from log message. 174 } 175 stream_ << std::endl; 176 std::string str_newline(stream_.str()); 177 178#if defined(OS_WIN) 179 OutputDebugStringA(str_newline.c_str()); 180#endif 181 fwrite(str_newline.data(), str_newline.size(), 1, stderr); 182 fflush(stderr); 183 184 if (severity_ == LOG_FATAL) { 185 abort(); 186 } 187} 188 189// writes the common header info to the stream 190void LogMessage::Init(const char* file, int line) { 191 std::string_view filename(file); 192 size_t last_slash_pos = filename.find_last_of("\\/"); 193 if (last_slash_pos != std::string_view::npos) 194 filename.remove_prefix(last_slash_pos + 1); 195 196 // TODO(darin): It might be nice if the columns were fixed width. 197 198 stream_ << '['; 199 stream_ << std::this_thread::get_id() << ':'; 200#if defined(OS_WIN) 201 SYSTEMTIME local_time; 202 GetLocalTime(&local_time); 203 stream_ << std::setfill('0') << std::setw(2) << local_time.wMonth 204 << std::setw(2) << local_time.wDay << '/' << std::setw(2) 205 << local_time.wHour << std::setw(2) << local_time.wMinute 206 << std::setw(2) << local_time.wSecond << '.' << std::setw(3) 207 << local_time.wMilliseconds << ':'; 208#elif defined(OS_POSIX) || defined(OS_FUCHSIA) 209 timeval tv; 210 gettimeofday(&tv, nullptr); 211 time_t t = tv.tv_sec; 212 struct tm local_time; 213 localtime_r(&t, &local_time); 214 struct tm* tm_time = &local_time; 215 stream_ << std::setfill('0') << std::setw(2) << 1 + tm_time->tm_mon 216 << std::setw(2) << tm_time->tm_mday << '/' << std::setw(2) 217 << tm_time->tm_hour << std::setw(2) << tm_time->tm_min << std::setw(2) 218 << tm_time->tm_sec << '.' << std::setw(6) << tv.tv_usec << ':'; 219#else 220#error Unsupported platform 221#endif 222 if (severity_ >= 0) 223 stream_ << log_severity_name(severity_); 224 else 225 stream_ << "VERBOSE" << -severity_; 226 227 stream_ << ":" << filename << "(" << line << ")] "; 228 229 message_start_ = stream_.str().length(); 230} 231 232#if defined(OS_WIN) 233// This has already been defined in the header, but defining it again as DWORD 234// ensures that the type used in the header is equivalent to DWORD. If not, 235// the redefinition is a compile error. 236typedef DWORD SystemErrorCode; 237#endif 238 239SystemErrorCode GetLastSystemErrorCode() { 240#if defined(OS_WIN) 241 return ::GetLastError(); 242#elif defined(OS_POSIX) || defined(OS_FUCHSIA) 243 return errno; 244#endif 245} 246 247std::string SystemErrorCodeToString(SystemErrorCode error_code) { 248#if defined(OS_WIN) 249 const int kErrorMessageBufferSize = 256; 250 char msgbuf[kErrorMessageBufferSize]; 251 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; 252 DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf, 253 std::size(msgbuf), nullptr); 254 if (len) { 255 // Messages returned by system end with line breaks. 256 return base::CollapseWhitespaceASCII(msgbuf, true) + 257 base::StringPrintf(" (0x%lX)", error_code); 258 } 259 return base::StringPrintf("Error (0x%lX) while retrieving error. (0x%lX)", 260 GetLastError(), error_code); 261#elif defined(OS_POSIX) || defined(OS_FUCHSIA) 262 return base::safe_strerror(error_code) + 263 base::StringPrintf(" (%d)", error_code); 264#endif // defined(OS_WIN) 265} 266 267#if defined(OS_WIN) 268Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, 269 int line, 270 LogSeverity severity, 271 SystemErrorCode err) 272 : err_(err), log_message_(file, line, severity) {} 273 274Win32ErrorLogMessage::~Win32ErrorLogMessage() { 275 stream() << ": " << SystemErrorCodeToString(err_); 276} 277#elif defined(OS_POSIX) || defined(OS_FUCHSIA) 278ErrnoLogMessage::ErrnoLogMessage(const char* file, 279 int line, 280 LogSeverity severity, 281 SystemErrorCode err) 282 : err_(err), log_message_(file, line, severity) {} 283 284ErrnoLogMessage::~ErrnoLogMessage() { 285 stream() << ": " << SystemErrorCodeToString(err_); 286} 287#endif // defined(OS_WIN) 288 289void RawLog(int level, const char* message) { 290 if (level >= g_min_log_level && message) { 291 size_t bytes_written = 0; 292 const size_t message_len = strlen(message); 293 int rv; 294 while (bytes_written < message_len) { 295 rv = HANDLE_EINTR(write(STDERR_FILENO, message + bytes_written, 296 message_len - bytes_written)); 297 if (rv < 0) { 298 // Give up, nothing we can do now. 299 break; 300 } 301 bytes_written += rv; 302 } 303 304 if (message_len > 0 && message[message_len - 1] != '\n') { 305 do { 306 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); 307 if (rv < 0) { 308 // Give up, nothing we can do now. 309 break; 310 } 311 } while (rv != 1); 312 } 313 } 314 315 if (level == LOG_FATAL) 316 abort(); 317} 318 319// This was defined at the beginning of this file. 320#undef write 321 322void LogErrorNotReached(const char* file, int line) { 323 LogMessage(file, line, LOG_ERROR).stream() << "NOTREACHED() hit."; 324} 325 326} // namespace logging 327