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 "base/macros.h" 11 #include "build/build_config.h" 12 13 #if defined(OS_WIN) 14 #include <io.h> 15 #include <windows.h> 16 #include "base/files/file_path.h" 17 #include "base/files/file_util.h" 18 typedef HANDLE FileHandle; 19 typedef HANDLE MutexHandle; 20 // Windows warns on using write(). It prefers _write(). 21 #define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count)) 22 // Windows doesn't define STDERR_FILENO. Define it here. 23 #define STDERR_FILENO 2 24 #elif defined(OS_MACOSX) 25 #include <asl.h> 26 #include <CoreFoundation/CoreFoundation.h> 27 #include <mach/mach.h> 28 #include <mach/mach_time.h> 29 #include <mach-o/dyld.h> 30 #elif defined(OS_POSIX) 31 #if defined(OS_NACL) 32 #include <sys/time.h> // timespec doesn't seem to be in <time.h> 33 #else 34 #include <sys/syscall.h> 35 #endif 36 #include <time.h> 37 #endif 38 39 #if defined(OS_POSIX) 40 #include <errno.h> 41 #include <paths.h> 42 #include <pthread.h> 43 #include <stdio.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include <sys/stat.h> 47 #include <unistd.h> 48 #define MAX_PATH PATH_MAX 49 typedef FILE* FileHandle; 50 typedef pthread_mutex_t* MutexHandle; 51 #endif 52 53 #include <algorithm> 54 #include <cassert> 55 #include <cstring> 56 #include <ctime> 57 #include <iomanip> 58 #include <ostream> 59 #include <string> 60 61 #include "base/base_switches.h" 62 #include "base/command_line.h" 63 #include "base/debug/alias.h" 64 #include "base/debug/debugger.h" 65 #include "base/debug/stack_trace.h" 66 #include "base/files/file_path.h" 67 #include "base/posix/eintr_wrapper.h" 68 #include "base/strings/string_piece.h" 69 #include "base/strings/string_util.h" 70 #include "base/strings/stringprintf.h" 71 #include "base/strings/sys_string_conversions.h" 72 #include "base/strings/utf_string_conversions.h" 73 #include "base/synchronization/lock_impl.h" 74 #include "base/threading/platform_thread.h" 75 #include "base/vlog.h" 76 #if defined(OS_POSIX) 77 #include "base/posix/safe_strerror.h" 78 #endif 79 80 #if defined(OS_ANDROID) || defined(__ANDROID__) 81 #include <android/log.h> 82 #endif 83 84 namespace logging { 85 86 namespace { 87 88 VlogInfo* g_vlog_info = nullptr; 89 VlogInfo* g_vlog_info_prev = nullptr; 90 91 const char* const log_severity_names[LOG_NUM_SEVERITIES] = { 92 "INFO", "WARNING", "ERROR", "FATAL" }; 93 94 const char* log_severity_name(int severity) { 95 if (severity >= 0 && severity < LOG_NUM_SEVERITIES) 96 return log_severity_names[severity]; 97 return "UNKNOWN"; 98 } 99 100 int g_min_log_level = 0; 101 102 LoggingDestination g_logging_destination = LOG_DEFAULT; 103 104 // For LOG_ERROR and above, always print to stderr. 105 const int kAlwaysPrintErrorLevel = LOG_ERROR; 106 107 // Which log file to use? This is initialized by InitLogging or 108 // will be lazily initialized to the default value when it is 109 // first needed. 110 #if defined(OS_WIN) 111 typedef std::wstring PathString; 112 #else 113 typedef std::string PathString; 114 #endif 115 PathString* g_log_file_name = nullptr; 116 117 // This file is lazily opened and the handle may be nullptr 118 FileHandle g_log_file = nullptr; 119 120 // What should be prepended to each message? 121 bool g_log_process_id = false; 122 bool g_log_thread_id = false; 123 bool g_log_timestamp = true; 124 bool g_log_tickcount = false; 125 126 // Should we pop up fatal debug messages in a dialog? 127 bool show_error_dialogs = false; 128 129 // An assert handler override specified by the client to be called instead of 130 // the debug message dialog and process termination. 131 LogAssertHandlerFunction log_assert_handler = nullptr; 132 // A log message handler that gets notified of every log message we process. 133 LogMessageHandlerFunction log_message_handler = nullptr; 134 135 // Helper functions to wrap platform differences. 136 137 int32_t CurrentProcessId() { 138 #if defined(OS_WIN) 139 return GetCurrentProcessId(); 140 #elif defined(OS_POSIX) 141 return getpid(); 142 #endif 143 } 144 145 uint64_t TickCount() { 146 #if defined(OS_WIN) 147 return GetTickCount(); 148 #elif defined(OS_MACOSX) 149 return mach_absolute_time(); 150 #elif defined(OS_NACL) 151 // NaCl sadly does not have _POSIX_TIMERS enabled in sys/features.h 152 // So we have to use clock() for now. 153 return clock(); 154 #elif defined(OS_POSIX) 155 struct timespec ts; 156 clock_gettime(CLOCK_MONOTONIC, &ts); 157 158 uint64_t absolute_micro = static_cast<int64_t>(ts.tv_sec) * 1000000 + 159 static_cast<int64_t>(ts.tv_nsec) / 1000; 160 161 return absolute_micro; 162 #endif 163 } 164 165 void DeleteFilePath(const PathString& log_name) { 166 #if defined(OS_WIN) 167 DeleteFile(log_name.c_str()); 168 #elif defined(OS_NACL) 169 // Do nothing; unlink() isn't supported on NaCl. 170 #else 171 unlink(log_name.c_str()); 172 #endif 173 } 174 175 PathString GetDefaultLogFile() { 176 #if defined(OS_WIN) 177 // On Windows we use the same path as the exe. 178 wchar_t module_name[MAX_PATH]; 179 GetModuleFileName(nullptr, module_name, MAX_PATH); 180 181 PathString log_name = module_name; 182 PathString::size_type last_backslash = log_name.rfind('\\', log_name.size()); 183 if (last_backslash != PathString::npos) 184 log_name.erase(last_backslash + 1); 185 log_name += L"debug.log"; 186 return log_name; 187 #elif defined(OS_POSIX) 188 // On other platforms we just use the current directory. 189 return PathString("debug.log"); 190 #endif 191 } 192 193 // We don't need locks on Windows for atomically appending to files. The OS 194 // provides this functionality. 195 #if !defined(OS_WIN) 196 // This class acts as a wrapper for locking the logging files. 197 // LoggingLock::Init() should be called from the main thread before any logging 198 // is done. Then whenever logging, be sure to have a local LoggingLock 199 // instance on the stack. This will ensure that the lock is unlocked upon 200 // exiting the frame. 201 // LoggingLocks can not be nested. 202 class LoggingLock { 203 public: 204 LoggingLock() { 205 LockLogging(); 206 } 207 208 ~LoggingLock() { 209 UnlockLogging(); 210 } 211 212 static void Init(LogLockingState lock_log, 213 const PathChar* /* new_log_file */) { 214 if (initialized) 215 return; 216 lock_log_file = lock_log; 217 218 if (lock_log_file != LOCK_LOG_FILE) 219 log_lock = new base::internal::LockImpl(); 220 221 initialized = true; 222 } 223 224 private: 225 static void LockLogging() { 226 if (lock_log_file == LOCK_LOG_FILE) { 227 #if defined(OS_POSIX) 228 pthread_mutex_lock(&log_mutex); 229 #endif 230 } else { 231 // use the lock 232 log_lock->Lock(); 233 } 234 } 235 236 static void UnlockLogging() { 237 if (lock_log_file == LOCK_LOG_FILE) { 238 #if defined(OS_POSIX) 239 pthread_mutex_unlock(&log_mutex); 240 #endif 241 } else { 242 log_lock->Unlock(); 243 } 244 } 245 246 // The lock is used if log file locking is false. It helps us avoid problems 247 // with multiple threads writing to the log file at the same time. Use 248 // LockImpl directly instead of using Lock, because Lock makes logging calls. 249 static base::internal::LockImpl* log_lock; 250 251 // When we don't use a lock, we are using a global mutex. We need to do this 252 // because LockFileEx is not thread safe. 253 #if defined(OS_POSIX) 254 static pthread_mutex_t log_mutex; 255 #endif 256 257 static bool initialized; 258 static LogLockingState lock_log_file; 259 }; 260 261 // static 262 bool LoggingLock::initialized = false; 263 // static 264 base::internal::LockImpl* LoggingLock::log_lock = nullptr; 265 // static 266 LogLockingState LoggingLock::lock_log_file = LOCK_LOG_FILE; 267 268 #if defined(OS_POSIX) 269 pthread_mutex_t LoggingLock::log_mutex = PTHREAD_MUTEX_INITIALIZER; 270 #endif 271 272 #endif // OS_WIN 273 274 // Called by logging functions to ensure that |g_log_file| is initialized 275 // and can be used for writing. Returns false if the file could not be 276 // initialized. |g_log_file| will be nullptr in this case. 277 bool InitializeLogFileHandle() { 278 if (g_log_file) 279 return true; 280 281 if (!g_log_file_name) { 282 // Nobody has called InitLogging to specify a debug log file, so here we 283 // initialize the log file name to a default. 284 g_log_file_name = new PathString(GetDefaultLogFile()); 285 } 286 287 if ((g_logging_destination & LOG_TO_FILE) != 0) { 288 #if defined(OS_WIN) 289 // The FILE_APPEND_DATA access mask ensures that the file is atomically 290 // appended to across accesses from multiple threads. 291 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364399(v=vs.85).aspx 292 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx 293 g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA, 294 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 295 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); 296 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { 297 // try the current directory 298 base::FilePath file_path; 299 if (!base::GetCurrentDirectory(&file_path)) 300 return false; 301 302 *g_log_file_name = file_path.Append( 303 FILE_PATH_LITERAL("debug.log")).value(); 304 305 g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA, 306 FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, 307 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); 308 if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) { 309 g_log_file = nullptr; 310 return false; 311 } 312 } 313 #elif defined(OS_POSIX) 314 g_log_file = fopen(g_log_file_name->c_str(), "a"); 315 if (g_log_file == nullptr) 316 return false; 317 #endif 318 } 319 320 return true; 321 } 322 323 void CloseFile(FileHandle log) { 324 #if defined(OS_WIN) 325 CloseHandle(log); 326 #else 327 fclose(log); 328 #endif 329 } 330 331 void CloseLogFileUnlocked() { 332 if (!g_log_file) 333 return; 334 335 CloseFile(g_log_file); 336 g_log_file = nullptr; 337 } 338 339 } // namespace 340 341 LoggingSettings::LoggingSettings() 342 : logging_dest(LOG_DEFAULT), 343 log_file(nullptr), 344 lock_log(LOCK_LOG_FILE), 345 delete_old(APPEND_TO_OLD_LOG_FILE) {} 346 347 bool BaseInitLoggingImpl(const LoggingSettings& settings) { 348 #if defined(OS_NACL) 349 // Can log only to the system debug log. 350 CHECK_EQ(settings.logging_dest & ~LOG_TO_SYSTEM_DEBUG_LOG, 0); 351 #endif 352 if (base::CommandLine::InitializedForCurrentProcess()) { 353 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); 354 // Don't bother initializing |g_vlog_info| unless we use one of the 355 // vlog switches. 356 if (command_line->HasSwitch(switches::kV) || 357 command_line->HasSwitch(switches::kVModule)) { 358 // NOTE: If |g_vlog_info| has already been initialized, it might be in use 359 // by another thread. Don't delete the old VLogInfo, just create a second 360 // one. We keep track of both to avoid memory leak warnings. 361 CHECK(!g_vlog_info_prev); 362 g_vlog_info_prev = g_vlog_info; 363 364 g_vlog_info = 365 new VlogInfo(command_line->GetSwitchValueASCII(switches::kV), 366 command_line->GetSwitchValueASCII(switches::kVModule), 367 &g_min_log_level); 368 } 369 } 370 371 g_logging_destination = settings.logging_dest; 372 373 // ignore file options unless logging to file is set. 374 if ((g_logging_destination & LOG_TO_FILE) == 0) 375 return true; 376 377 #if !defined(OS_WIN) 378 LoggingLock::Init(settings.lock_log, settings.log_file); 379 LoggingLock logging_lock; 380 #endif 381 382 // Calling InitLogging twice or after some log call has already opened the 383 // default log file will re-initialize to the new options. 384 CloseLogFileUnlocked(); 385 386 if (!g_log_file_name) 387 g_log_file_name = new PathString(); 388 *g_log_file_name = settings.log_file; 389 if (settings.delete_old == DELETE_OLD_LOG_FILE) 390 DeleteFilePath(*g_log_file_name); 391 392 return InitializeLogFileHandle(); 393 } 394 395 void SetMinLogLevel(int level) { 396 g_min_log_level = std::min(LOG_FATAL, level); 397 } 398 399 int GetMinLogLevel() { 400 return g_min_log_level; 401 } 402 403 bool ShouldCreateLogMessage(int severity) { 404 if (severity < g_min_log_level) 405 return false; 406 407 // Return true here unless we know ~LogMessage won't do anything. Note that 408 // ~LogMessage writes to stderr if severity_ >= kAlwaysPrintErrorLevel, even 409 // when g_logging_destination is LOG_NONE. 410 return g_logging_destination != LOG_NONE || log_message_handler || 411 severity >= kAlwaysPrintErrorLevel; 412 } 413 414 int GetVlogVerbosity() { 415 return std::max(-1, LOG_INFO - GetMinLogLevel()); 416 } 417 418 int GetVlogLevelHelper(const char* file, size_t N) { 419 DCHECK_GT(N, 0U); 420 // Note: |g_vlog_info| may change on a different thread during startup 421 // (but will always be valid or nullptr). 422 VlogInfo* vlog_info = g_vlog_info; 423 return vlog_info ? 424 vlog_info->GetVlogLevel(base::StringPiece(file, N - 1)) : 425 GetVlogVerbosity(); 426 } 427 428 void SetLogItems(bool enable_process_id, bool enable_thread_id, 429 bool enable_timestamp, bool enable_tickcount) { 430 g_log_process_id = enable_process_id; 431 g_log_thread_id = enable_thread_id; 432 g_log_timestamp = enable_timestamp; 433 g_log_tickcount = enable_tickcount; 434 } 435 436 void SetShowErrorDialogs(bool enable_dialogs) { 437 show_error_dialogs = enable_dialogs; 438 } 439 440 void SetLogAssertHandler(LogAssertHandlerFunction handler) { 441 log_assert_handler = handler; 442 } 443 444 void SetLogMessageHandler(LogMessageHandlerFunction handler) { 445 log_message_handler = handler; 446 } 447 448 LogMessageHandlerFunction GetLogMessageHandler() { 449 return log_message_handler; 450 } 451 452 // Explicit instantiations for commonly used comparisons. 453 template std::string* MakeCheckOpString<int, int>( 454 const int&, const int&, const char* names); 455 template std::string* MakeCheckOpString<unsigned long, unsigned long>( 456 const unsigned long&, const unsigned long&, const char* names); 457 template std::string* MakeCheckOpString<unsigned long, unsigned int>( 458 const unsigned long&, const unsigned int&, const char* names); 459 template std::string* MakeCheckOpString<unsigned int, unsigned long>( 460 const unsigned int&, const unsigned long&, const char* names); 461 template std::string* MakeCheckOpString<std::string, std::string>( 462 const std::string&, const std::string&, const char* name); 463 464 #if !defined(NDEBUG) 465 // Displays a message box to the user with the error message in it. 466 // Used for fatal messages, where we close the app simultaneously. 467 // This is for developers only; we don't use this in circumstances 468 // (like release builds) where users could see it, since users don't 469 // understand these messages anyway. 470 void DisplayDebugMessageInDialog(const std::string& str) { 471 if (str.empty()) 472 return; 473 474 if (!show_error_dialogs) 475 return; 476 477 #if defined(OS_WIN) 478 MessageBoxW(nullptr, base::UTF8ToUTF16(str).c_str(), L"Fatal error", 479 MB_OK | MB_ICONHAND | MB_TOPMOST); 480 #else 481 // We intentionally don't implement a dialog on other platforms. 482 // You can just look at stderr. 483 #endif // defined(OS_WIN) 484 } 485 #endif // !defined(NDEBUG) 486 487 #if defined(OS_WIN) 488 LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) { 489 } 490 491 LogMessage::SaveLastError::~SaveLastError() { 492 ::SetLastError(last_error_); 493 } 494 #endif // defined(OS_WIN) 495 496 LogMessage::LogMessage(const char* file, int line, LogSeverity severity) 497 : severity_(severity), file_(file), line_(line) { 498 Init(file, line); 499 } 500 501 LogMessage::LogMessage(const char* file, int line, const char* condition) 502 : severity_(LOG_FATAL), file_(file), line_(line) { 503 Init(file, line); 504 stream_ << "Check failed: " << condition << ". "; 505 } 506 507 LogMessage::LogMessage(const char* file, int line, std::string* result) 508 : severity_(LOG_FATAL), file_(file), line_(line) { 509 Init(file, line); 510 stream_ << "Check failed: " << *result; 511 delete result; 512 } 513 514 LogMessage::LogMessage(const char* file, int line, LogSeverity severity, 515 std::string* result) 516 : severity_(severity), file_(file), line_(line) { 517 Init(file, line); 518 stream_ << "Check failed: " << *result; 519 delete result; 520 } 521 522 LogMessage::~LogMessage() { 523 #if !defined(OFFICIAL_BUILD) && !defined(OS_NACL) && !defined(__UCLIBC__) 524 if (severity_ == LOG_FATAL && !base::debug::BeingDebugged()) { 525 // Include a stack trace on a fatal, unless a debugger is attached. 526 base::debug::StackTrace trace; 527 stream_ << std::endl; // Newline to separate from log message. 528 trace.OutputToStream(&stream_); 529 } 530 #endif 531 stream_ << std::endl; 532 std::string str_newline(stream_.str()); 533 534 // Give any log message handler first dibs on the message. 535 if (log_message_handler && 536 log_message_handler(severity_, file_, line_, 537 message_start_, str_newline)) { 538 // The handler took care of it, no further processing. 539 return; 540 } 541 542 if ((g_logging_destination & LOG_TO_SYSTEM_DEBUG_LOG) != 0) { 543 #if defined(OS_WIN) 544 OutputDebugStringA(str_newline.c_str()); 545 #elif defined(OS_MACOSX) 546 // In LOG_TO_SYSTEM_DEBUG_LOG mode, log messages are always written to 547 // stderr. If stderr is /dev/null, also log via ASL (Apple System Log). If 548 // there's something weird about stderr, assume that log messages are going 549 // nowhere and log via ASL too. Messages logged via ASL show up in 550 // Console.app. 551 // 552 // Programs started by launchd, as UI applications normally are, have had 553 // stderr connected to /dev/null since OS X 10.8. Prior to that, stderr was 554 // a pipe to launchd, which logged what it received (see log_redirect_fd in 555 // 10.7.5 launchd-392.39/launchd/src/launchd_core_logic.c). 556 // 557 // Another alternative would be to determine whether stderr is a pipe to 558 // launchd and avoid logging via ASL only in that case. See 10.7.5 559 // CF-635.21/CFUtilities.c also_do_stderr(). This would result in logging to 560 // both stderr and ASL even in tests, where it's undesirable to log to the 561 // system log at all. 562 // 563 // Note that the ASL client by default discards messages whose levels are 564 // below ASL_LEVEL_NOTICE. It's possible to change that with 565 // asl_set_filter(), but this is pointless because syslogd normally applies 566 // the same filter. 567 const bool log_via_asl = []() { 568 struct stat stderr_stat; 569 if (fstat(fileno(stderr), &stderr_stat) == -1) { 570 return true; 571 } 572 if (!S_ISCHR(stderr_stat.st_mode)) { 573 return false; 574 } 575 576 struct stat dev_null_stat; 577 if (stat(_PATH_DEVNULL, &dev_null_stat) == -1) { 578 return true; 579 } 580 581 return !S_ISCHR(dev_null_stat.st_mode) || 582 stderr_stat.st_rdev == dev_null_stat.st_rdev; 583 }(); 584 585 if (log_via_asl) { 586 // Log roughly the same way that CFLog() and NSLog() would. See 10.10.5 587 // CF-1153.18/CFUtilities.c __CFLogCString(). 588 // 589 // The ASL facility is set to the main bundle ID if available. Otherwise, 590 // "com.apple.console" is used. 591 CFBundleRef main_bundle = CFBundleGetMainBundle(); 592 CFStringRef main_bundle_id_cf = 593 main_bundle ? CFBundleGetIdentifier(main_bundle) : nullptr; 594 std::string asl_facility = 595 main_bundle_id_cf ? base::SysCFStringRefToUTF8(main_bundle_id_cf) 596 : std::string("com.apple.console"); 597 598 class ASLClient { 599 public: 600 explicit ASLClient(const std::string& asl_facility) 601 : client_(asl_open(nullptr, 602 asl_facility.c_str(), 603 ASL_OPT_NO_DELAY)) {} 604 ~ASLClient() { asl_close(client_); } 605 606 aslclient get() const { return client_; } 607 608 private: 609 aslclient client_; 610 DISALLOW_COPY_AND_ASSIGN(ASLClient); 611 } asl_client(asl_facility); 612 613 class ASLMessage { 614 public: 615 ASLMessage() : message_(asl_new(ASL_TYPE_MSG)) {} 616 ~ASLMessage() { asl_free(message_); } 617 618 aslmsg get() const { return message_; } 619 620 private: 621 aslmsg message_; 622 DISALLOW_COPY_AND_ASSIGN(ASLMessage); 623 } asl_message; 624 625 // By default, messages are only readable by the admin group. Explicitly 626 // make them readable by the user generating the messages. 627 char euid_string[12]; 628 snprintf(euid_string, arraysize(euid_string), "%d", geteuid()); 629 asl_set(asl_message.get(), ASL_KEY_READ_UID, euid_string); 630 631 // Map Chrome log severities to ASL log levels. 632 const char* const asl_level_string = [](LogSeverity severity) { 633 // ASL_LEVEL_* are ints, but ASL needs equivalent strings. This 634 // non-obvious two-step macro trick achieves what's needed. 635 // https://gcc.gnu.org/onlinedocs/cpp/Stringification.html 636 #define ASL_LEVEL_STR(level) ASL_LEVEL_STR_X(level) 637 #define ASL_LEVEL_STR_X(level) #level 638 switch (severity) { 639 case LOG_INFO: 640 return ASL_LEVEL_STR(ASL_LEVEL_INFO); 641 case LOG_WARNING: 642 return ASL_LEVEL_STR(ASL_LEVEL_WARNING); 643 case LOG_ERROR: 644 return ASL_LEVEL_STR(ASL_LEVEL_ERR); 645 case LOG_FATAL: 646 return ASL_LEVEL_STR(ASL_LEVEL_CRIT); 647 default: 648 return severity < 0 ? ASL_LEVEL_STR(ASL_LEVEL_DEBUG) 649 : ASL_LEVEL_STR(ASL_LEVEL_NOTICE); 650 } 651 #undef ASL_LEVEL_STR 652 #undef ASL_LEVEL_STR_X 653 }(severity_); 654 asl_set(asl_message.get(), ASL_KEY_LEVEL, asl_level_string); 655 656 asl_set(asl_message.get(), ASL_KEY_MSG, str_newline.c_str()); 657 658 asl_send(asl_client.get(), asl_message.get()); 659 } 660 #elif defined(OS_ANDROID) || defined(__ANDROID__) 661 android_LogPriority priority = 662 (severity_ < 0) ? ANDROID_LOG_VERBOSE : ANDROID_LOG_UNKNOWN; 663 switch (severity_) { 664 case LOG_INFO: 665 priority = ANDROID_LOG_INFO; 666 break; 667 case LOG_WARNING: 668 priority = ANDROID_LOG_WARN; 669 break; 670 case LOG_ERROR: 671 priority = ANDROID_LOG_ERROR; 672 break; 673 case LOG_FATAL: 674 priority = ANDROID_LOG_FATAL; 675 break; 676 } 677 #if defined(OS_ANDROID) 678 __android_log_write(priority, "chromium", str_newline.c_str()); 679 #else 680 __android_log_write( 681 priority, 682 base::CommandLine::InitializedForCurrentProcess() ? 683 base::CommandLine::ForCurrentProcess()-> 684 GetProgram().BaseName().value().c_str() : nullptr, 685 str_newline.c_str()); 686 #endif // defined(OS_ANDROID) 687 #endif 688 ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); 689 fflush(stderr); 690 } else if (severity_ >= kAlwaysPrintErrorLevel) { 691 // When we're only outputting to a log file, above a certain log level, we 692 // should still output to stderr so that we can better detect and diagnose 693 // problems with unit tests, especially on the buildbots. 694 ignore_result(fwrite(str_newline.data(), str_newline.size(), 1, stderr)); 695 fflush(stderr); 696 } 697 698 // write to log file 699 if ((g_logging_destination & LOG_TO_FILE) != 0) { 700 // We can have multiple threads and/or processes, so try to prevent them 701 // from clobbering each other's writes. 702 // If the client app did not call InitLogging, and the lock has not 703 // been created do it now. We do this on demand, but if two threads try 704 // to do this at the same time, there will be a race condition to create 705 // the lock. This is why InitLogging should be called from the main 706 // thread at the beginning of execution. 707 #if !defined(OS_WIN) 708 LoggingLock::Init(LOCK_LOG_FILE, nullptr); 709 LoggingLock logging_lock; 710 #endif 711 if (InitializeLogFileHandle()) { 712 #if defined(OS_WIN) 713 DWORD num_written; 714 WriteFile(g_log_file, 715 static_cast<const void*>(str_newline.c_str()), 716 static_cast<DWORD>(str_newline.length()), 717 &num_written, 718 nullptr); 719 #else 720 ignore_result(fwrite( 721 str_newline.data(), str_newline.size(), 1, g_log_file)); 722 fflush(g_log_file); 723 #endif 724 } 725 } 726 727 if (severity_ == LOG_FATAL) { 728 // Ensure the first characters of the string are on the stack so they 729 // are contained in minidumps for diagnostic purposes. 730 char str_stack[1024]; 731 str_newline.copy(str_stack, arraysize(str_stack)); 732 base::debug::Alias(str_stack); 733 734 if (log_assert_handler) { 735 // Make a copy of the string for the handler out of paranoia. 736 log_assert_handler(std::string(stream_.str())); 737 } else { 738 // Don't use the string with the newline, get a fresh version to send to 739 // the debug message process. We also don't display assertions to the 740 // user in release mode. The enduser can't do anything with this 741 // information, and displaying message boxes when the application is 742 // hosed can cause additional problems. 743 #ifndef NDEBUG 744 if (!base::debug::BeingDebugged()) { 745 // Displaying a dialog is unnecessary when debugging and can complicate 746 // debugging. 747 DisplayDebugMessageInDialog(stream_.str()); 748 } 749 #endif 750 // Crash the process to generate a dump. 751 base::debug::BreakDebugger(); 752 } 753 } 754 } 755 756 // writes the common header info to the stream 757 void LogMessage::Init(const char* file, int line) { 758 base::StringPiece filename(file); 759 size_t last_slash_pos = filename.find_last_of("\\/"); 760 if (last_slash_pos != base::StringPiece::npos) 761 filename.remove_prefix(last_slash_pos + 1); 762 763 // TODO(darin): It might be nice if the columns were fixed width. 764 765 stream_ << '['; 766 if (g_log_process_id) 767 stream_ << CurrentProcessId() << ':'; 768 if (g_log_thread_id) 769 stream_ << base::PlatformThread::CurrentId() << ':'; 770 if (g_log_timestamp) { 771 time_t t = time(nullptr); 772 struct tm local_time; 773 memset(&local_time, 0, sizeof(local_time)); 774 #ifdef _MSC_VER 775 localtime_s(&local_time, &t); 776 #else 777 localtime_r(&t, &local_time); 778 #endif 779 struct tm* tm_time = &local_time; 780 stream_ << std::setfill('0') 781 << std::setw(2) << 1 + tm_time->tm_mon 782 << std::setw(2) << tm_time->tm_mday 783 << '/' 784 << std::setw(2) << tm_time->tm_hour 785 << std::setw(2) << tm_time->tm_min 786 << std::setw(2) << tm_time->tm_sec 787 << ':'; 788 } 789 if (g_log_tickcount) 790 stream_ << TickCount() << ':'; 791 if (severity_ >= 0) 792 stream_ << log_severity_name(severity_); 793 else 794 stream_ << "VERBOSE" << -severity_; 795 796 stream_ << ":" << filename << "(" << line << ")] "; 797 798 message_start_ = stream_.str().length(); 799 } 800 801 #if defined(OS_WIN) 802 // This has already been defined in the header, but defining it again as DWORD 803 // ensures that the type used in the header is equivalent to DWORD. If not, 804 // the redefinition is a compile error. 805 typedef DWORD SystemErrorCode; 806 #endif 807 808 SystemErrorCode GetLastSystemErrorCode() { 809 #if defined(OS_WIN) 810 return ::GetLastError(); 811 #elif defined(OS_POSIX) 812 return errno; 813 #else 814 #error Not implemented 815 #endif 816 } 817 818 #if defined(OS_WIN) 819 BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) { 820 const int kErrorMessageBufferSize = 256; 821 char msgbuf[kErrorMessageBufferSize]; 822 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; 823 DWORD len = FormatMessageA(flags, nullptr, error_code, 0, msgbuf, 824 arraysize(msgbuf), nullptr); 825 if (len) { 826 // Messages returned by system end with line breaks. 827 return base::CollapseWhitespaceASCII(msgbuf, true) + 828 base::StringPrintf(" (0x%X)", error_code); 829 } 830 return base::StringPrintf("Error (0x%X) while retrieving error. (0x%X)", 831 GetLastError(), error_code); 832 } 833 #elif defined(OS_POSIX) 834 BASE_EXPORT std::string SystemErrorCodeToString(SystemErrorCode error_code) { 835 return base::safe_strerror(error_code); 836 } 837 #else 838 #error Not implemented 839 #endif // defined(OS_WIN) 840 841 842 #if defined(OS_WIN) 843 Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, 844 int line, 845 LogSeverity severity, 846 SystemErrorCode err) 847 : err_(err), 848 log_message_(file, line, severity) { 849 } 850 851 Win32ErrorLogMessage::~Win32ErrorLogMessage() { 852 stream() << ": " << SystemErrorCodeToString(err_); 853 // We're about to crash (CHECK). Put |err_| on the stack (by placing it in a 854 // field) and use Alias in hopes that it makes it into crash dumps. 855 DWORD last_error = err_; 856 base::debug::Alias(&last_error); 857 } 858 #elif defined(OS_POSIX) 859 ErrnoLogMessage::ErrnoLogMessage(const char* file, 860 int line, 861 LogSeverity severity, 862 SystemErrorCode err) 863 : err_(err), 864 log_message_(file, line, severity) { 865 } 866 867 ErrnoLogMessage::~ErrnoLogMessage() { 868 stream() << ": " << SystemErrorCodeToString(err_); 869 } 870 #endif // defined(OS_WIN) 871 872 void CloseLogFile() { 873 #if !defined(OS_WIN) 874 LoggingLock logging_lock; 875 #endif 876 CloseLogFileUnlocked(); 877 } 878 879 void RawLog(int level, const char* message) { 880 if (level >= g_min_log_level) { 881 size_t bytes_written = 0; 882 const size_t message_len = strlen(message); 883 int rv; 884 while (bytes_written < message_len) { 885 rv = HANDLE_EINTR( 886 write(STDERR_FILENO, message + bytes_written, 887 message_len - bytes_written)); 888 if (rv < 0) { 889 // Give up, nothing we can do now. 890 break; 891 } 892 bytes_written += rv; 893 } 894 895 if (message_len > 0 && message[message_len - 1] != '\n') { 896 do { 897 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); 898 if (rv < 0) { 899 // Give up, nothing we can do now. 900 break; 901 } 902 } while (rv != 1); 903 } 904 } 905 906 if (level == LOG_FATAL) 907 base::debug::BreakDebugger(); 908 } 909 910 // This was defined at the beginning of this file. 911 #undef write 912 913 #if defined(OS_WIN) 914 bool IsLoggingToFileEnabled() { 915 return g_logging_destination & LOG_TO_FILE; 916 } 917 918 std::wstring GetLogFileFullPath() { 919 if (g_log_file_name) 920 return *g_log_file_name; 921 return std::wstring(); 922 } 923 #endif 924 925 BASE_EXPORT void LogErrorNotReached(const char* file, int line) { 926 LogMessage(file, line, LOG_ERROR).stream() 927 << "NOTREACHED() hit."; 928 } 929 930 } // namespace logging 931 932 std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { 933 return out << base::WideToUTF8(wstr); 934 } 935