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