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