logging.cc revision 00d26a728db2814620f390b418a7d6325ce5aca6
1// Copyright (c) 2006-2009 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#if defined(OS_WIN) 8#include <io.h> 9#include <windows.h> 10typedef HANDLE FileHandle; 11typedef HANDLE MutexHandle; 12// Windows warns on using write(). It prefers _write(). 13#define write(fd, buf, count) _write(fd, buf, static_cast<unsigned int>(count)) 14// Windows doesn't define STDERR_FILENO. Define it here. 15#define STDERR_FILENO 2 16#elif defined(OS_MACOSX) 17#include <CoreFoundation/CoreFoundation.h> 18#include <mach/mach.h> 19#include <mach/mach_time.h> 20#include <mach-o/dyld.h> 21#elif defined(OS_POSIX) 22#include <sys/syscall.h> 23#include <time.h> 24#endif 25 26#if defined(OS_POSIX) 27#include <errno.h> 28#include <stdlib.h> 29#include <stdio.h> 30#include <string.h> 31#include <unistd.h> 32#define MAX_PATH PATH_MAX 33typedef FILE* FileHandle; 34#include "pthread.h" 35typedef pthread_mutex_t* MutexHandle; 36#endif 37 38#include <ctime> 39#include <iomanip> 40#include <cstring> 41#include <algorithm> 42 43#include "base/base_switches.h" 44#include "base/command_line.h" 45#include "base/debug_util.h" 46#include "base/eintr_wrapper.h" 47#include "base/lock_impl.h" 48#if defined(OS_POSIX) 49#include "base/safe_strerror_posix.h" 50#endif 51#include "base/process_util.h" 52#include "base/string_piece.h" 53#include "base/string_util.h" 54#include "base/utf_string_conversions.h" 55 56namespace logging { 57 58bool g_enable_dcheck = false; 59 60const char* const log_severity_names[LOG_NUM_SEVERITIES] = { 61 "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" }; 62 63int min_log_level = 0; 64LogLockingState lock_log_file = LOCK_LOG_FILE; 65 66// The default set here for logging_destination will only be used if 67// InitLogging is not called. On Windows, use a file next to the exe; 68// on POSIX platforms, where it may not even be possible to locate the 69// executable on disk, use stderr. 70#if defined(OS_WIN) 71LoggingDestination logging_destination = LOG_ONLY_TO_FILE; 72#elif defined(OS_POSIX) 73LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG; 74#endif 75 76const int kMaxFilteredLogLevel = LOG_WARNING; 77std::string* log_filter_prefix; 78 79// For LOG_ERROR and above, always print to stderr. 80const int kAlwaysPrintErrorLevel = LOG_ERROR; 81 82// Which log file to use? This is initialized by InitLogging or 83// will be lazily initialized to the default value when it is 84// first needed. 85#if defined(OS_WIN) 86typedef wchar_t PathChar; 87typedef std::wstring PathString; 88#else 89typedef char PathChar; 90typedef std::string PathString; 91#endif 92PathString* log_file_name = NULL; 93 94// this file is lazily opened and the handle may be NULL 95FileHandle log_file = NULL; 96 97// what should be prepended to each message? 98bool log_process_id = false; 99bool log_thread_id = false; 100bool log_timestamp = true; 101bool log_tickcount = false; 102 103// An assert handler override specified by the client to be called instead of 104// the debug message dialog and process termination. 105LogAssertHandlerFunction log_assert_handler = NULL; 106// An report handler override specified by the client to be called instead of 107// the debug message dialog. 108LogReportHandlerFunction log_report_handler = NULL; 109// A log message handler that gets notified of every log message we process. 110LogMessageHandlerFunction log_message_handler = NULL; 111 112// The lock is used if log file locking is false. It helps us avoid problems 113// with multiple threads writing to the log file at the same time. Use 114// LockImpl directly instead of using Lock, because Lock makes logging calls. 115static LockImpl* log_lock = NULL; 116 117// When we don't use a lock, we are using a global mutex. We need to do this 118// because LockFileEx is not thread safe. 119#if defined(OS_WIN) 120MutexHandle log_mutex = NULL; 121#elif defined(OS_POSIX) 122pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER; 123#endif 124 125// Helper functions to wrap platform differences. 126 127int32 CurrentProcessId() { 128#if defined(OS_WIN) 129 return GetCurrentProcessId(); 130#elif defined(OS_POSIX) 131 return getpid(); 132#endif 133} 134 135int32 CurrentThreadId() { 136#if defined(OS_WIN) 137 return GetCurrentThreadId(); 138#elif defined(OS_MACOSX) 139 return mach_thread_self(); 140#elif defined(OS_LINUX) 141 return syscall(__NR_gettid); 142#elif defined(OS_FREEBSD) 143 // TODO(BSD): find a better thread ID 144 return reinterpret_cast<int64>(pthread_self()); 145#endif 146} 147 148uint64 TickCount() { 149#if defined(OS_WIN) 150 return GetTickCount(); 151#elif defined(OS_MACOSX) 152 return mach_absolute_time(); 153#elif defined(OS_POSIX) 154 struct timespec ts; 155 clock_gettime(CLOCK_MONOTONIC, &ts); 156 157 uint64 absolute_micro = 158 static_cast<int64>(ts.tv_sec) * 1000000 + 159 static_cast<int64>(ts.tv_nsec) / 1000; 160 161 return absolute_micro; 162#endif 163} 164 165void CloseFile(FileHandle log) { 166#if defined(OS_WIN) 167 CloseHandle(log); 168#else 169 fclose(log); 170#endif 171} 172 173void DeleteFilePath(const PathString& log_name) { 174#if defined(OS_WIN) 175 DeleteFile(log_name.c_str()); 176#else 177 unlink(log_name.c_str()); 178#endif 179} 180 181// Called by logging functions to ensure that debug_file is initialized 182// and can be used for writing. Returns false if the file could not be 183// initialized. debug_file will be NULL in this case. 184bool InitializeLogFileHandle() { 185 if (log_file) 186 return true; 187 188 if (!log_file_name) { 189 // Nobody has called InitLogging to specify a debug log file, so here we 190 // initialize the log file name to a default. 191#if defined(OS_WIN) 192 // On Windows we use the same path as the exe. 193 wchar_t module_name[MAX_PATH]; 194 GetModuleFileName(NULL, module_name, MAX_PATH); 195 log_file_name = new std::wstring(module_name); 196 std::wstring::size_type last_backslash = 197 log_file_name->rfind('\\', log_file_name->size()); 198 if (last_backslash != std::wstring::npos) 199 log_file_name->erase(last_backslash + 1); 200 *log_file_name += L"debug.log"; 201#elif defined(OS_POSIX) 202 // On other platforms we just use the current directory. 203 log_file_name = new std::string("debug.log"); 204#endif 205 } 206 207 if (logging_destination == LOG_ONLY_TO_FILE || 208 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) { 209#if defined(OS_WIN) 210 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE, 211 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 212 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 213 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { 214 // try the current directory 215 log_file = CreateFile(L".\\debug.log", GENERIC_WRITE, 216 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, 217 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 218 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) { 219 log_file = NULL; 220 return false; 221 } 222 } 223 SetFilePointer(log_file, 0, 0, FILE_END); 224#elif defined(OS_POSIX) 225 log_file = fopen(log_file_name->c_str(), "a"); 226 if (log_file == NULL) 227 return false; 228#endif 229 } 230 231 return true; 232} 233 234void InitLogMutex() { 235#if defined(OS_WIN) 236 if (!log_mutex) { 237 // \ is not a legal character in mutex names so we replace \ with / 238 std::wstring safe_name(*log_file_name); 239 std::replace(safe_name.begin(), safe_name.end(), '\\', '/'); 240 std::wstring t(L"Global\\"); 241 t.append(safe_name); 242 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str()); 243 } 244#elif defined(OS_POSIX) 245 // statically initialized 246#endif 247} 248 249void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest, 250 LogLockingState lock_log, OldFileDeletionState delete_old) { 251 g_enable_dcheck = 252#ifdef ANDROID 253 false; 254#else 255 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK); 256#endif // ANDROID 257 258 if (log_file) { 259 // calling InitLogging twice or after some log call has already opened the 260 // default log file will re-initialize to the new options 261 CloseFile(log_file); 262 log_file = NULL; 263 } 264 265 lock_log_file = lock_log; 266 logging_destination = logging_dest; 267 268 // ignore file options if logging is disabled or only to system 269 if (logging_destination == LOG_NONE || 270 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG) 271 return; 272 273 if (!log_file_name) 274 log_file_name = new PathString(); 275 *log_file_name = new_log_file; 276 if (delete_old == DELETE_OLD_LOG_FILE) 277 DeleteFilePath(*log_file_name); 278 279 if (lock_log_file == LOCK_LOG_FILE) { 280 InitLogMutex(); 281 } else if (!log_lock) { 282 log_lock = new LockImpl(); 283 } 284 285 InitializeLogFileHandle(); 286} 287 288void SetMinLogLevel(int level) { 289 min_log_level = level; 290} 291 292int GetMinLogLevel() { 293 return min_log_level; 294} 295 296void SetLogFilterPrefix(const char* filter) { 297 if (log_filter_prefix) { 298 delete log_filter_prefix; 299 log_filter_prefix = NULL; 300 } 301 302 if (filter) 303 log_filter_prefix = new std::string(filter); 304} 305 306void SetLogItems(bool enable_process_id, bool enable_thread_id, 307 bool enable_timestamp, bool enable_tickcount) { 308 log_process_id = enable_process_id; 309 log_thread_id = enable_thread_id; 310 log_timestamp = enable_timestamp; 311 log_tickcount = enable_tickcount; 312} 313 314void SetLogAssertHandler(LogAssertHandlerFunction handler) { 315 log_assert_handler = handler; 316} 317 318void SetLogReportHandler(LogReportHandlerFunction handler) { 319 log_report_handler = handler; 320} 321 322void SetLogMessageHandler(LogMessageHandlerFunction handler) { 323 log_message_handler = handler; 324} 325 326 327// Displays a message box to the user with the error message in it. 328// Used for fatal messages, where we close the app simultaneously. 329void DisplayDebugMessageInDialog(const std::string& str) { 330 if (str.empty()) 331 return; 332 333#if defined(OS_WIN) 334 // For Windows programs, it's possible that the message loop is 335 // messed up on a fatal error, and creating a MessageBox will cause 336 // that message loop to be run. Instead, we try to spawn another 337 // process that displays its command line. We look for "Debug 338 // Message.exe" in the same directory as the application. If it 339 // exists, we use it, otherwise, we use a regular message box. 340 wchar_t prog_name[MAX_PATH]; 341 GetModuleFileNameW(NULL, prog_name, MAX_PATH); 342 wchar_t* backslash = wcsrchr(prog_name, '\\'); 343 if (backslash) 344 backslash[1] = 0; 345 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe"); 346 347 std::wstring cmdline = UTF8ToWide(str); 348 if (cmdline.empty()) 349 return; 350 351 STARTUPINFO startup_info; 352 memset(&startup_info, 0, sizeof(startup_info)); 353 startup_info.cb = sizeof(startup_info); 354 355 PROCESS_INFORMATION process_info; 356 if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL, 357 NULL, &startup_info, &process_info)) { 358 WaitForSingleObject(process_info.hProcess, INFINITE); 359 CloseHandle(process_info.hThread); 360 CloseHandle(process_info.hProcess); 361 } else { 362 // debug process broken, let's just do a message box 363 MessageBoxW(NULL, &cmdline[0], L"Fatal error", 364 MB_OK | MB_ICONHAND | MB_TOPMOST); 365 } 366#elif defined(USE_X11) 367 // Shell out to xmessage, which behaves like debug_message.exe, but is 368 // way more retro. We could use zenity/kdialog but then we're starting 369 // to get into needing to check the desktop env and this dialog should 370 // only be coming up in Very Bad situations. 371 std::vector<std::string> argv; 372 argv.push_back("xmessage"); 373 argv.push_back(str); 374 base::LaunchApp(argv, base::file_handle_mapping_vector(), true /* wait */, 375 NULL); 376#else 377 // http://code.google.com/p/chromium/issues/detail?id=37026 378 NOTIMPLEMENTED(); 379#endif 380} 381 382#if defined(OS_WIN) 383LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) { 384} 385 386LogMessage::SaveLastError::~SaveLastError() { 387 ::SetLastError(last_error_); 388} 389#endif // defined(OS_WIN) 390 391LogMessage::LogMessage(const char* file, int line, LogSeverity severity, 392 int ctr) 393 : severity_(severity) { 394 Init(file, line); 395} 396 397LogMessage::LogMessage(const char* file, int line, const CheckOpString& result) 398 : severity_(LOG_FATAL) { 399 Init(file, line); 400 stream_ << "Check failed: " << (*result.str_); 401} 402 403LogMessage::LogMessage(const char* file, int line, LogSeverity severity, 404 const CheckOpString& result) 405 : severity_(severity) { 406 Init(file, line); 407 stream_ << "Check failed: " << (*result.str_); 408} 409 410LogMessage::LogMessage(const char* file, int line) 411 : severity_(LOG_INFO) { 412 Init(file, line); 413} 414 415LogMessage::LogMessage(const char* file, int line, LogSeverity severity) 416 : severity_(severity) { 417 Init(file, line); 418} 419 420// writes the common header info to the stream 421void LogMessage::Init(const char* file, int line) { 422 // log only the filename 423 const char* last_slash = strrchr(file, '\\'); 424 if (last_slash) 425 file = last_slash + 1; 426 427 // TODO(darin): It might be nice if the columns were fixed width. 428 429 stream_ << '['; 430 if (log_process_id) 431 stream_ << CurrentProcessId() << ':'; 432 if (log_thread_id) 433 stream_ << CurrentThreadId() << ':'; 434 if (log_timestamp) { 435 time_t t = time(NULL); 436 struct tm local_time = {0}; 437#if _MSC_VER >= 1400 438 localtime_s(&local_time, &t); 439#else 440 localtime_r(&t, &local_time); 441#endif 442 struct tm* tm_time = &local_time; 443 stream_ << std::setfill('0') 444 << std::setw(2) << 1 + tm_time->tm_mon 445 << std::setw(2) << tm_time->tm_mday 446 << '/' 447 << std::setw(2) << tm_time->tm_hour 448 << std::setw(2) << tm_time->tm_min 449 << std::setw(2) << tm_time->tm_sec 450 << ':'; 451 } 452 if (log_tickcount) 453 stream_ << TickCount() << ':'; 454 stream_ << log_severity_names[severity_] << ":" << file << 455 "(" << line << ")] "; 456 457 message_start_ = stream_.tellp(); 458} 459 460LogMessage::~LogMessage() { 461 // TODO(brettw) modify the macros so that nothing is executed when the log 462 // level is too high. 463 if (severity_ < min_log_level) 464 return; 465 466#ifndef NDEBUG 467 if (severity_ == LOG_FATAL) { 468 // Include a stack trace on a fatal. 469 StackTrace trace; 470 stream_ << std::endl; // Newline to separate from log message. 471 trace.OutputToStream(&stream_); 472 } 473#endif 474 stream_ << std::endl; 475 std::string str_newline(stream_.str()); 476 477 // Give any log message handler first dibs on the message. 478 if (log_message_handler && log_message_handler(severity_, str_newline)) 479 return; 480 481 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel && 482 str_newline.compare(message_start_, log_filter_prefix->size(), 483 log_filter_prefix->data()) != 0) { 484 return; 485 } 486 487 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG || 488 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) { 489#if defined(OS_WIN) 490 OutputDebugStringA(str_newline.c_str()); 491 if (severity_ >= kAlwaysPrintErrorLevel) { 492#else 493 { 494#endif 495 // TODO(erikkay): this interferes with the layout tests since it grabs 496 // stderr and stdout and diffs them against known data. Our info and warn 497 // logs add noise to that. Ideally, the layout tests would set the log 498 // level to ignore anything below error. When that happens, we should 499 // take this fprintf out of the #else so that Windows users can benefit 500 // from the output when running tests from the command-line. In the 501 // meantime, we leave this in for Mac and Linux, but until this is fixed 502 // they won't be able to pass any layout tests that have info or warn 503 // logs. See http://b/1343647 504 fprintf(stderr, "%s", str_newline.c_str()); 505 fflush(stderr); 506 } 507 } else if (severity_ >= kAlwaysPrintErrorLevel) { 508 // When we're only outputting to a log file, above a certain log level, we 509 // should still output to stderr so that we can better detect and diagnose 510 // problems with unit tests, especially on the buildbots. 511 fprintf(stderr, "%s", str_newline.c_str()); 512 fflush(stderr); 513 } 514 515 // write to log file 516 if (logging_destination != LOG_NONE && 517 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG && 518 InitializeLogFileHandle()) { 519 // We can have multiple threads and/or processes, so try to prevent them 520 // from clobbering each other's writes. 521 if (lock_log_file == LOCK_LOG_FILE) { 522 // Ensure that the mutex is initialized in case the client app did not 523 // call InitLogging. This is not thread safe. See below. 524 InitLogMutex(); 525 526#if defined(OS_WIN) 527 ::WaitForSingleObject(log_mutex, INFINITE); 528 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't 529 // abort the process here. UI tests might be crashy sometimes, 530 // and aborting the test binary only makes the problem worse. 531 // We also don't use LOG macros because that might lead to an infinite 532 // loop. For more info see http://crbug.com/18028. 533#elif defined(OS_POSIX) 534 pthread_mutex_lock(&log_mutex); 535#endif 536 } else { 537 // use the lock 538 if (!log_lock) { 539 // The client app did not call InitLogging, and so the lock has not 540 // been created. We do this on demand, but if two threads try to do 541 // this at the same time, there will be a race condition to create 542 // the lock. This is why InitLogging should be called from the main 543 // thread at the beginning of execution. 544 log_lock = new LockImpl(); 545 } 546 log_lock->Lock(); 547 } 548 549#if defined(OS_WIN) 550 SetFilePointer(log_file, 0, 0, SEEK_END); 551 DWORD num_written; 552 WriteFile(log_file, 553 static_cast<const void*>(str_newline.c_str()), 554 static_cast<DWORD>(str_newline.length()), 555 &num_written, 556 NULL); 557#else 558 fprintf(log_file, "%s", str_newline.c_str()); 559 fflush(log_file); 560#endif 561 562 if (lock_log_file == LOCK_LOG_FILE) { 563#if defined(OS_WIN) 564 ReleaseMutex(log_mutex); 565#elif defined(OS_POSIX) 566 pthread_mutex_unlock(&log_mutex); 567#endif 568 } else { 569 log_lock->Unlock(); 570 } 571 } 572 573 if (severity_ == LOG_FATAL) { 574 // display a message or break into the debugger on a fatal error 575 if (DebugUtil::BeingDebugged()) { 576 DebugUtil::BreakDebugger(); 577 } else { 578 if (log_assert_handler) { 579 // make a copy of the string for the handler out of paranoia 580 log_assert_handler(std::string(stream_.str())); 581 } else { 582 // Don't use the string with the newline, get a fresh version to send to 583 // the debug message process. We also don't display assertions to the 584 // user in release mode. The enduser can't do anything with this 585 // information, and displaying message boxes when the application is 586 // hosed can cause additional problems. 587#ifndef NDEBUG 588 DisplayDebugMessageInDialog(stream_.str()); 589#endif 590 // Crash the process to generate a dump. 591 DebugUtil::BreakDebugger(); 592 } 593 } 594 } else if (severity_ == LOG_ERROR_REPORT) { 595 // We are here only if the user runs with --enable-dcheck in release mode. 596 if (log_report_handler) { 597 log_report_handler(std::string(stream_.str())); 598 } else { 599 DisplayDebugMessageInDialog(stream_.str()); 600 } 601 } 602} 603 604#if defined(OS_WIN) 605// This has already been defined in the header, but defining it again as DWORD 606// ensures that the type used in the header is equivalent to DWORD. If not, 607// the redefinition is a compile error. 608typedef DWORD SystemErrorCode; 609#endif 610 611SystemErrorCode GetLastSystemErrorCode() { 612#if defined(OS_WIN) 613 return ::GetLastError(); 614#elif defined(OS_POSIX) 615 return errno; 616#else 617#error Not implemented 618#endif 619} 620 621#if defined(OS_WIN) 622Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, 623 int line, 624 LogSeverity severity, 625 SystemErrorCode err, 626 const char* module) 627 : err_(err), 628 module_(module), 629 log_message_(file, line, severity) { 630} 631 632Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file, 633 int line, 634 LogSeverity severity, 635 SystemErrorCode err) 636 : err_(err), 637 module_(NULL), 638 log_message_(file, line, severity) { 639} 640 641Win32ErrorLogMessage::~Win32ErrorLogMessage() { 642 const int error_message_buffer_size = 256; 643 char msgbuf[error_message_buffer_size]; 644 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM; 645 HMODULE hmod; 646 if (module_) { 647 hmod = GetModuleHandleA(module_); 648 if (hmod) { 649 flags |= FORMAT_MESSAGE_FROM_HMODULE; 650 } else { 651 // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL 652 // so it will not call GetModuleHandle, so recursive errors are 653 // impossible. 654 DPLOG(WARNING) << "Couldn't open module " << module_ 655 << " for error message query"; 656 } 657 } else { 658 hmod = NULL; 659 } 660 DWORD len = FormatMessageA(flags, 661 hmod, 662 err_, 663 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 664 msgbuf, 665 sizeof(msgbuf) / sizeof(msgbuf[0]), 666 NULL); 667 if (len) { 668 while ((len > 0) && 669 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) { 670 msgbuf[--len] = 0; 671 } 672 stream() << ": " << msgbuf; 673 } else { 674 stream() << ": Error " << GetLastError() << " while retrieving error " 675 << err_; 676 } 677} 678#elif defined(OS_POSIX) 679ErrnoLogMessage::ErrnoLogMessage(const char* file, 680 int line, 681 LogSeverity severity, 682 SystemErrorCode err) 683 : err_(err), 684 log_message_(file, line, severity) { 685} 686 687ErrnoLogMessage::~ErrnoLogMessage() { 688 stream() << ": " << safe_strerror(err_); 689} 690#endif // OS_WIN 691 692void CloseLogFile() { 693 if (!log_file) 694 return; 695 696 CloseFile(log_file); 697 log_file = NULL; 698} 699 700void RawLog(int level, const char* message) { 701 if (level >= min_log_level) { 702 size_t bytes_written = 0; 703 const size_t message_len = strlen(message); 704 int rv; 705 while (bytes_written < message_len) { 706 rv = HANDLE_EINTR( 707 write(STDERR_FILENO, message + bytes_written, 708 message_len - bytes_written)); 709 if (rv < 0) { 710 // Give up, nothing we can do now. 711 break; 712 } 713 bytes_written += rv; 714 } 715 716 if (message_len > 0 && message[message_len - 1] != '\n') { 717 do { 718 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1)); 719 if (rv < 0) { 720 // Give up, nothing we can do now. 721 break; 722 } 723 } while (rv != 1); 724 } 725 } 726 727 if (level == LOG_FATAL) 728 DebugUtil::BreakDebugger(); 729} 730 731} // namespace logging 732 733std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) { 734 return out << WideToUTF8(std::wstring(wstr)); 735} 736