blob: f90a3695f2bd55be2554ece0617edc5ec12c9796 [file] [log] [blame]
[email protected]f1633932010-08-17 23:05:281// Copyright (c) 2010 The Chromium Authors. All rights reserved.
license.botbf09a502008-08-24 00:55:552// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
initial.commitd7cae122008-07-26 21:49:384
[email protected]b16ef312008-08-19 18:36:235#include "base/logging.h"
[email protected]f6abeba2008-08-08 13:27:286
[email protected]b16ef312008-08-19 18:36:237#if defined(OS_WIN)
[email protected]e36ddc82009-12-08 04:22:508#include <io.h>
[email protected]f6abeba2008-08-08 13:27:289#include <windows.h>
10typedef HANDLE FileHandle;
11typedef HANDLE MutexHandle;
[email protected]e36ddc82009-12-08 04:22:5012// 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
[email protected]052f1b52008-11-06 21:43:0716#elif defined(OS_MACOSX)
[email protected]f6abeba2008-08-08 13:27:2817#include <CoreFoundation/CoreFoundation.h>
18#include <mach/mach.h>
19#include <mach/mach_time.h>
20#include <mach-o/dyld.h>
[email protected]e43eddf12009-12-29 00:32:5221#elif defined(OS_POSIX)
[email protected]052f1b52008-11-06 21:43:0722#include <sys/syscall.h>
23#include <time.h>
[email protected]614e9fa2008-08-11 22:52:5924#endif
25
26#if defined(OS_POSIX)
[email protected]d8617a62009-10-09 23:52:2027#include <errno.h>
[email protected]166326c62010-08-05 15:50:2328#include <pthread.h>
[email protected]f6abeba2008-08-08 13:27:2829#include <stdlib.h>
30#include <stdio.h>
31#include <string.h>
32#include <unistd.h>
33#define MAX_PATH PATH_MAX
34typedef FILE* FileHandle;
35typedef pthread_mutex_t* MutexHandle;
36#endif
37
initial.commitd7cae122008-07-26 21:49:3838#include <ctime>
39#include <iomanip>
40#include <cstring>
initial.commitd7cae122008-07-26 21:49:3841#include <algorithm>
[email protected]b16ef312008-08-19 18:36:2342
initial.commitd7cae122008-07-26 21:49:3843#include "base/base_switches.h"
44#include "base/command_line.h"
[email protected]1ffe08c12008-08-13 11:15:1145#include "base/debug_util.h"
[email protected]e36ddc82009-12-08 04:22:5046#include "base/eintr_wrapper.h"
initial.commitd7cae122008-07-26 21:49:3847#include "base/lock_impl.h"
[email protected]d8617a62009-10-09 23:52:2048#if defined(OS_POSIX)
49#include "base/safe_strerror_posix.h"
50#endif
[email protected]d81baca42010-03-01 13:10:2251#include "base/process_util.h"
[email protected]4bdaceb42008-08-19 13:19:2452#include "base/string_piece.h"
[email protected]047a03f2009-10-07 02:10:2053#include "base/utf_string_conversions.h"
[email protected]52a261f2009-03-03 15:01:1254
initial.commitd7cae122008-07-26 21:49:3855namespace logging {
56
57bool g_enable_dcheck = false;
58
59const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
[email protected]fb62a532009-02-12 01:19:0560 "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
initial.commitd7cae122008-07-26 21:49:3861
62int min_log_level = 0;
[email protected]cba21962010-08-31 22:35:5563LogLockingState lock_log_file = LOCK_LOG_FILE;
[email protected]1d8c2702008-08-19 23:39:3264
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.
[email protected]4c0040c2008-08-15 01:04:1169#if defined(OS_WIN)
[email protected]fe613522008-08-22 17:09:3470LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
[email protected]4c0040c2008-08-15 01:04:1171#elif defined(OS_POSIX)
[email protected]1d8c2702008-08-19 23:39:3272LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
[email protected]4c0040c2008-08-15 01:04:1173#endif
initial.commitd7cae122008-07-26 21:49:3874
75const int kMaxFilteredLogLevel = LOG_WARNING;
[email protected]614e9fa2008-08-11 22:52:5976std::string* log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:3877
[email protected]a33c9892008-08-25 20:10:3178// For LOG_ERROR and above, always print to stderr.
79const int kAlwaysPrintErrorLevel = LOG_ERROR;
80
[email protected]614e9fa2008-08-11 22:52:5981// Which log file to use? This is initialized by InitLogging or
initial.commitd7cae122008-07-26 21:49:3882// will be lazily initialized to the default value when it is
83// first needed.
[email protected]f6abeba2008-08-08 13:27:2884#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:5985typedef std::wstring PathString;
[email protected]f6abeba2008-08-08 13:27:2886#else
[email protected]614e9fa2008-08-11 22:52:5987typedef std::string PathString;
[email protected]f6abeba2008-08-08 13:27:2888#endif
[email protected]614e9fa2008-08-11 22:52:5989PathString* log_file_name = NULL;
initial.commitd7cae122008-07-26 21:49:3890
91// this file is lazily opened and the handle may be NULL
[email protected]f6abeba2008-08-08 13:27:2892FileHandle log_file = NULL;
initial.commitd7cae122008-07-26 21:49:3893
94// what should be prepended to each message?
95bool log_process_id = false;
96bool log_thread_id = false;
97bool log_timestamp = true;
98bool log_tickcount = false;
99
[email protected]81e0a852010-08-17 00:38:12100// Should we pop up fatal debug messages in a dialog?
101bool show_error_dialogs = false;
102
initial.commitd7cae122008-07-26 21:49:38103// An assert handler override specified by the client to be called instead of
[email protected]fb62a532009-02-12 01:19:05104// the debug message dialog and process termination.
initial.commitd7cae122008-07-26 21:49:38105LogAssertHandlerFunction log_assert_handler = NULL;
[email protected]fb62a532009-02-12 01:19:05106// An report handler override specified by the client to be called instead of
107// the debug message dialog.
108LogReportHandlerFunction log_report_handler = NULL;
[email protected]2b07b8412009-11-25 15:26:34109// A log message handler that gets notified of every log message we process.
110LogMessageHandlerFunction log_message_handler = NULL;
initial.commitd7cae122008-07-26 21:49:38111
[email protected]cba21962010-08-31 22:35:55112// 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
[email protected]f6abeba2008-08-08 13:27:28125// Helper functions to wrap platform differences.
126
[email protected]f8588472008-11-05 23:17:24127int32 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();
[email protected]052f1b52008-11-06 21:43:07140#elif defined(OS_LINUX)
141 return syscall(__NR_gettid);
[email protected]e43eddf12009-12-29 00:32:52142#elif defined(OS_FREEBSD)
143 // TODO(BSD): find a better thread ID
144 return reinterpret_cast<int64>(pthread_self());
[email protected]f8588472008-11-05 23:17:24145#endif
146}
147
148uint64 TickCount() {
149#if defined(OS_WIN)
150 return GetTickCount();
151#elif defined(OS_MACOSX)
152 return mach_absolute_time();
[email protected]e43eddf12009-12-29 00:32:52153#elif defined(OS_POSIX)
[email protected]052f1b52008-11-06 21:43:07154 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;
[email protected]f8588472008-11-05 23:17:24162#endif
163}
164
[email protected]f6abeba2008-08-08 13:27:28165void CloseFile(FileHandle log) {
166#if defined(OS_WIN)
167 CloseHandle(log);
168#else
169 fclose(log);
170#endif
171}
172
[email protected]614e9fa2008-08-11 22:52:59173void DeleteFilePath(const PathString& log_name) {
[email protected]f6abeba2008-08-08 13:27:28174#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:59175 DeleteFile(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28176#else
[email protected]614e9fa2008-08-11 22:52:59177 unlink(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28178#endif
179}
initial.commitd7cae122008-07-26 21:49:38180
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
[email protected]614e9fa2008-08-11 22:52:59188 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.
[email protected]cba21962010-08-31 22:35:55191#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
initial.commitd7cae122008-07-26 21:49:38205 }
206
[email protected]1d8c2702008-08-19 23:39:32207 if (logging_destination == LOG_ONLY_TO_FILE ||
208 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
[email protected]614e9fa2008-08-11 22:52:59209#if defined(OS_WIN)
[email protected]1d8c2702008-08-19 23:39:32210 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
initial.commitd7cae122008-07-26 21:49:38211 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
212 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
213 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
[email protected]1d8c2702008-08-19 23:39:32214 // 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 }
initial.commitd7cae122008-07-26 21:49:38222 }
[email protected]1d8c2702008-08-19 23:39:32223 SetFilePointer(log_file, 0, 0, FILE_END);
[email protected]78c6dd62009-06-08 23:29:11224#elif defined(OS_POSIX)
225 log_file = fopen(log_file_name->c_str(), "a");
226 if (log_file == NULL)
227 return false;
[email protected]f6abeba2008-08-08 13:27:28228#endif
[email protected]1d8c2702008-08-19 23:39:32229 }
230
initial.commitd7cae122008-07-26 21:49:38231 return true;
232}
233
[email protected]cba21962010-08-31 22:35:55234void 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
[email protected]ff3d0c32010-08-23 19:57:46249void BaseInitLoggingImpl(const PathChar* new_log_file,
250 LoggingDestination logging_dest,
251 LogLockingState lock_log,
252 OldFileDeletionState delete_old) {
[email protected]bb975362009-01-21 01:00:22253 g_enable_dcheck =
254 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
initial.commitd7cae122008-07-26 21:49:38255
256 if (log_file) {
257 // calling InitLogging twice or after some log call has already opened the
258 // default log file will re-initialize to the new options
[email protected]f6abeba2008-08-08 13:27:28259 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38260 log_file = NULL;
261 }
262
[email protected]cba21962010-08-31 22:35:55263 lock_log_file = lock_log;
initial.commitd7cae122008-07-26 21:49:38264 logging_destination = logging_dest;
265
266 // ignore file options if logging is disabled or only to system
267 if (logging_destination == LOG_NONE ||
268 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
269 return;
270
[email protected]614e9fa2008-08-11 22:52:59271 if (!log_file_name)
272 log_file_name = new PathString();
273 *log_file_name = new_log_file;
initial.commitd7cae122008-07-26 21:49:38274 if (delete_old == DELETE_OLD_LOG_FILE)
[email protected]614e9fa2008-08-11 22:52:59275 DeleteFilePath(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38276
[email protected]cba21962010-08-31 22:35:55277 if (lock_log_file == LOCK_LOG_FILE) {
278 InitLogMutex();
279 } else if (!log_lock) {
280 log_lock = new LockImpl();
281 }
[email protected]b3c572a2010-08-31 21:48:58282
[email protected]cba21962010-08-31 22:35:55283 InitializeLogFileHandle();
initial.commitd7cae122008-07-26 21:49:38284}
285
286void SetMinLogLevel(int level) {
287 min_log_level = level;
288}
289
290int GetMinLogLevel() {
291 return min_log_level;
292}
293
294void SetLogFilterPrefix(const char* filter) {
295 if (log_filter_prefix) {
[email protected]614e9fa2008-08-11 22:52:59296 delete log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:38297 log_filter_prefix = NULL;
298 }
299
[email protected]614e9fa2008-08-11 22:52:59300 if (filter)
301 log_filter_prefix = new std::string(filter);
initial.commitd7cae122008-07-26 21:49:38302}
303
304void SetLogItems(bool enable_process_id, bool enable_thread_id,
305 bool enable_timestamp, bool enable_tickcount) {
306 log_process_id = enable_process_id;
307 log_thread_id = enable_thread_id;
308 log_timestamp = enable_timestamp;
309 log_tickcount = enable_tickcount;
310}
311
[email protected]81e0a852010-08-17 00:38:12312void SetShowErrorDialogs(bool enable_dialogs) {
313 show_error_dialogs = enable_dialogs;
314}
315
initial.commitd7cae122008-07-26 21:49:38316void SetLogAssertHandler(LogAssertHandlerFunction handler) {
317 log_assert_handler = handler;
318}
319
[email protected]fb62a532009-02-12 01:19:05320void SetLogReportHandler(LogReportHandlerFunction handler) {
321 log_report_handler = handler;
322}
323
[email protected]2b07b8412009-11-25 15:26:34324void SetLogMessageHandler(LogMessageHandlerFunction handler) {
325 log_message_handler = handler;
326}
327
328
[email protected]d81baca42010-03-01 13:10:22329// Displays a message box to the user with the error message in it.
330// Used for fatal messages, where we close the app simultaneously.
331void DisplayDebugMessageInDialog(const std::string& str) {
initial.commitd7cae122008-07-26 21:49:38332 if (str.empty())
333 return;
334
[email protected]81e0a852010-08-17 00:38:12335 if (!show_error_dialogs)
[email protected]846ed9c32010-07-29 20:33:44336 return;
337
[email protected]f6abeba2008-08-08 13:27:28338#if defined(OS_WIN)
[email protected]d81baca42010-03-01 13:10:22339 // For Windows programs, it's possible that the message loop is
340 // messed up on a fatal error, and creating a MessageBox will cause
341 // that message loop to be run. Instead, we try to spawn another
342 // process that displays its command line. We look for "Debug
343 // Message.exe" in the same directory as the application. If it
344 // exists, we use it, otherwise, we use a regular message box.
initial.commitd7cae122008-07-26 21:49:38345 wchar_t prog_name[MAX_PATH];
346 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
347 wchar_t* backslash = wcsrchr(prog_name, '\\');
348 if (backslash)
349 backslash[1] = 0;
350 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
351
[email protected]047a03f2009-10-07 02:10:20352 std::wstring cmdline = UTF8ToWide(str);
[email protected]3ca4214c12009-03-25 22:12:02353 if (cmdline.empty())
354 return;
initial.commitd7cae122008-07-26 21:49:38355
356 STARTUPINFO startup_info;
357 memset(&startup_info, 0, sizeof(startup_info));
358 startup_info.cb = sizeof(startup_info);
359
360 PROCESS_INFORMATION process_info;
[email protected]3ca4214c12009-03-25 22:12:02361 if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
initial.commitd7cae122008-07-26 21:49:38362 NULL, &startup_info, &process_info)) {
363 WaitForSingleObject(process_info.hProcess, INFINITE);
364 CloseHandle(process_info.hThread);
365 CloseHandle(process_info.hProcess);
366 } else {
367 // debug process broken, let's just do a message box
[email protected]3ca4214c12009-03-25 22:12:02368 MessageBoxW(NULL, &cmdline[0], L"Fatal error",
initial.commitd7cae122008-07-26 21:49:38369 MB_OK | MB_ICONHAND | MB_TOPMOST);
370 }
[email protected]81e0a852010-08-17 00:38:12371#elif defined(USE_X11) && !defined(OS_CHROMEOS)
[email protected]d81baca42010-03-01 13:10:22372 // Shell out to xmessage, which behaves like debug_message.exe, but is
373 // way more retro. We could use zenity/kdialog but then we're starting
374 // to get into needing to check the desktop env and this dialog should
375 // only be coming up in Very Bad situations.
376 std::vector<std::string> argv;
377 argv.push_back("xmessage");
378 argv.push_back(str);
379 base::LaunchApp(argv, base::file_handle_mapping_vector(), true /* wait */,
380 NULL);
[email protected]f6abeba2008-08-08 13:27:28381#else
[email protected]d81baca42010-03-01 13:10:22382 // http://code.google.com/p/chromium/issues/detail?id=37026
383 NOTIMPLEMENTED();
[email protected]f6abeba2008-08-08 13:27:28384#endif
initial.commitd7cae122008-07-26 21:49:38385}
386
[email protected]3f85caa2009-04-14 16:52:11387#if defined(OS_WIN)
388LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
389}
390
391LogMessage::SaveLastError::~SaveLastError() {
392 ::SetLastError(last_error_);
393}
394#endif // defined(OS_WIN)
395
initial.commitd7cae122008-07-26 21:49:38396LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
397 int ctr)
398 : severity_(severity) {
399 Init(file, line);
400}
401
402LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
403 : severity_(LOG_FATAL) {
404 Init(file, line);
405 stream_ << "Check failed: " << (*result.str_);
406}
407
[email protected]fb62a532009-02-12 01:19:05408LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
409 const CheckOpString& result)
410 : severity_(severity) {
411 Init(file, line);
412 stream_ << "Check failed: " << (*result.str_);
413}
414
initial.commitd7cae122008-07-26 21:49:38415LogMessage::LogMessage(const char* file, int line)
416 : severity_(LOG_INFO) {
417 Init(file, line);
418}
419
420LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
421 : severity_(severity) {
422 Init(file, line);
423}
424
425// writes the common header info to the stream
426void LogMessage::Init(const char* file, int line) {
427 // log only the filename
428 const char* last_slash = strrchr(file, '\\');
429 if (last_slash)
430 file = last_slash + 1;
431
432 // TODO(darin): It might be nice if the columns were fixed width.
433
434 stream_ << '[';
435 if (log_process_id)
[email protected]f8588472008-11-05 23:17:24436 stream_ << CurrentProcessId() << ':';
initial.commitd7cae122008-07-26 21:49:38437 if (log_thread_id)
[email protected]f8588472008-11-05 23:17:24438 stream_ << CurrentThreadId() << ':';
initial.commitd7cae122008-07-26 21:49:38439 if (log_timestamp) {
[email protected]defcd8f32009-05-13 00:03:43440 time_t t = time(NULL);
initial.commitd7cae122008-07-26 21:49:38441 struct tm local_time = {0};
[email protected]defcd8f32009-05-13 00:03:43442#if _MSC_VER >= 1400
initial.commitd7cae122008-07-26 21:49:38443 localtime_s(&local_time, &t);
initial.commitd7cae122008-07-26 21:49:38444#else
[email protected]defcd8f32009-05-13 00:03:43445 localtime_r(&t, &local_time);
initial.commitd7cae122008-07-26 21:49:38446#endif
[email protected]defcd8f32009-05-13 00:03:43447 struct tm* tm_time = &local_time;
initial.commitd7cae122008-07-26 21:49:38448 stream_ << std::setfill('0')
449 << std::setw(2) << 1 + tm_time->tm_mon
450 << std::setw(2) << tm_time->tm_mday
451 << '/'
452 << std::setw(2) << tm_time->tm_hour
453 << std::setw(2) << tm_time->tm_min
454 << std::setw(2) << tm_time->tm_sec
455 << ':';
456 }
457 if (log_tickcount)
[email protected]f8588472008-11-05 23:17:24458 stream_ << TickCount() << ':';
[email protected]52a261f2009-03-03 15:01:12459 stream_ << log_severity_names[severity_] << ":" << file <<
460 "(" << line << ")] ";
initial.commitd7cae122008-07-26 21:49:38461
462 message_start_ = stream_.tellp();
463}
464
465LogMessage::~LogMessage() {
466 // TODO(brettw) modify the macros so that nothing is executed when the log
467 // level is too high.
468 if (severity_ < min_log_level)
469 return;
470
[email protected]d1ccc35a2010-03-24 05:03:24471#ifndef NDEBUG
472 if (severity_ == LOG_FATAL) {
473 // Include a stack trace on a fatal.
474 StackTrace trace;
475 stream_ << std::endl; // Newline to separate from log message.
476 trace.OutputToStream(&stream_);
477 }
[email protected]1d8c2702008-08-19 23:39:32478#endif
[email protected]d1ccc35a2010-03-24 05:03:24479 stream_ << std::endl;
480 std::string str_newline(stream_.str());
481
[email protected]2b07b8412009-11-25 15:26:34482 // Give any log message handler first dibs on the message.
483 if (log_message_handler && log_message_handler(severity_, str_newline))
484 return;
initial.commitd7cae122008-07-26 21:49:38485
486 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
[email protected]614e9fa2008-08-11 22:52:59487 str_newline.compare(message_start_, log_filter_prefix->size(),
488 log_filter_prefix->data()) != 0) {
initial.commitd7cae122008-07-26 21:49:38489 return;
490 }
491
492 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
[email protected]f6abeba2008-08-08 13:27:28493 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
494#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38495 OutputDebugStringA(str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02496 if (severity_ >= kAlwaysPrintErrorLevel) {
497#else
498 {
[email protected]107bc0f12008-08-26 17:48:18499#endif
[email protected]1ce41052009-12-02 00:34:02500 // TODO(erikkay): this interferes with the layout tests since it grabs
501 // stderr and stdout and diffs them against known data. Our info and warn
502 // logs add noise to that. Ideally, the layout tests would set the log
503 // level to ignore anything below error. When that happens, we should
504 // take this fprintf out of the #else so that Windows users can benefit
505 // from the output when running tests from the command-line. In the
506 // meantime, we leave this in for Mac and Linux, but until this is fixed
507 // they won't be able to pass any layout tests that have info or warn
508 // logs. See http://b/1343647
509 fprintf(stderr, "%s", str_newline.c_str());
510 fflush(stderr);
511 }
[email protected]a33c9892008-08-25 20:10:31512 } else if (severity_ >= kAlwaysPrintErrorLevel) {
513 // When we're only outputting to a log file, above a certain log level, we
514 // should still output to stderr so that we can better detect and diagnose
515 // problems with unit tests, especially on the buildbots.
516 fprintf(stderr, "%s", str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02517 fflush(stderr);
[email protected]f6abeba2008-08-08 13:27:28518 }
[email protected]52a261f2009-03-03 15:01:12519
initial.commitd7cae122008-07-26 21:49:38520 // write to log file
521 if (logging_destination != LOG_NONE &&
[email protected]cba21962010-08-31 22:35:55522 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
523 InitializeLogFileHandle()) {
524 // We can have multiple threads and/or processes, so try to prevent them
525 // from clobbering each other's writes.
526 if (lock_log_file == LOCK_LOG_FILE) {
527 // Ensure that the mutex is initialized in case the client app did not
528 // call InitLogging. This is not thread safe. See below.
529 InitLogMutex();
530
[email protected]f6abeba2008-08-08 13:27:28531#if defined(OS_WIN)
[email protected]cba21962010-08-31 22:35:55532 ::WaitForSingleObject(log_mutex, INFINITE);
533 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
534 // abort the process here. UI tests might be crashy sometimes,
535 // and aborting the test binary only makes the problem worse.
536 // We also don't use LOG macros because that might lead to an infinite
537 // loop. For more info see http://crbug.com/18028.
538#elif defined(OS_POSIX)
539 pthread_mutex_lock(&log_mutex);
[email protected]f6abeba2008-08-08 13:27:28540#endif
[email protected]cba21962010-08-31 22:35:55541 } else {
542 // use the lock
543 if (!log_lock) {
544 // The client app did not call InitLogging, and so the lock has not
545 // been created. We do this on demand, but if two threads try to do
546 // this at the same time, there will be a race condition to create
547 // the lock. This is why InitLogging should be called from the main
548 // thread at the beginning of execution.
549 log_lock = new LockImpl();
550 }
551 log_lock->Lock();
552 }
553
554#if defined(OS_WIN)
555 SetFilePointer(log_file, 0, 0, SEEK_END);
556 DWORD num_written;
557 WriteFile(log_file,
558 static_cast<const void*>(str_newline.c_str()),
559 static_cast<DWORD>(str_newline.length()),
560 &num_written,
561 NULL);
562#else
563 fprintf(log_file, "%s", str_newline.c_str());
564 fflush(log_file);
565#endif
566
567 if (lock_log_file == LOCK_LOG_FILE) {
568#if defined(OS_WIN)
569 ReleaseMutex(log_mutex);
570#elif defined(OS_POSIX)
571 pthread_mutex_unlock(&log_mutex);
572#endif
573 } else {
574 log_lock->Unlock();
initial.commitd7cae122008-07-26 21:49:38575 }
576 }
577
578 if (severity_ == LOG_FATAL) {
579 // display a message or break into the debugger on a fatal error
[email protected]1ffe08c12008-08-13 11:15:11580 if (DebugUtil::BeingDebugged()) {
581 DebugUtil::BreakDebugger();
582 } else {
initial.commitd7cae122008-07-26 21:49:38583 if (log_assert_handler) {
584 // make a copy of the string for the handler out of paranoia
585 log_assert_handler(std::string(stream_.str()));
586 } else {
[email protected]4d5901272008-11-06 00:33:50587 // Don't use the string with the newline, get a fresh version to send to
588 // the debug message process. We also don't display assertions to the
589 // user in release mode. The enduser can't do anything with this
590 // information, and displaying message boxes when the application is
591 // hosed can cause additional problems.
592#ifndef NDEBUG
[email protected]d81baca42010-03-01 13:10:22593 DisplayDebugMessageInDialog(stream_.str());
[email protected]4d5901272008-11-06 00:33:50594#endif
initial.commitd7cae122008-07-26 21:49:38595 // Crash the process to generate a dump.
[email protected]1ffe08c12008-08-13 11:15:11596 DebugUtil::BreakDebugger();
initial.commitd7cae122008-07-26 21:49:38597 }
598 }
[email protected]fb62a532009-02-12 01:19:05599 } else if (severity_ == LOG_ERROR_REPORT) {
600 // We are here only if the user runs with --enable-dcheck in release mode.
601 if (log_report_handler) {
602 log_report_handler(std::string(stream_.str()));
603 } else {
[email protected]d81baca42010-03-01 13:10:22604 DisplayDebugMessageInDialog(stream_.str());
[email protected]fb62a532009-02-12 01:19:05605 }
initial.commitd7cae122008-07-26 21:49:38606 }
607}
608
[email protected]d8617a62009-10-09 23:52:20609#if defined(OS_WIN)
610// This has already been defined in the header, but defining it again as DWORD
611// ensures that the type used in the header is equivalent to DWORD. If not,
612// the redefinition is a compile error.
613typedef DWORD SystemErrorCode;
614#endif
615
616SystemErrorCode GetLastSystemErrorCode() {
617#if defined(OS_WIN)
618 return ::GetLastError();
619#elif defined(OS_POSIX)
620 return errno;
621#else
622#error Not implemented
623#endif
624}
625
626#if defined(OS_WIN)
627Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
628 int line,
629 LogSeverity severity,
630 SystemErrorCode err,
631 const char* module)
632 : err_(err),
633 module_(module),
634 log_message_(file, line, severity) {
635}
636
637Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
638 int line,
639 LogSeverity severity,
640 SystemErrorCode err)
641 : err_(err),
642 module_(NULL),
643 log_message_(file, line, severity) {
644}
645
646Win32ErrorLogMessage::~Win32ErrorLogMessage() {
647 const int error_message_buffer_size = 256;
648 char msgbuf[error_message_buffer_size];
649 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
650 HMODULE hmod;
651 if (module_) {
652 hmod = GetModuleHandleA(module_);
653 if (hmod) {
654 flags |= FORMAT_MESSAGE_FROM_HMODULE;
655 } else {
656 // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
657 // so it will not call GetModuleHandle, so recursive errors are
658 // impossible.
659 DPLOG(WARNING) << "Couldn't open module " << module_
660 << " for error message query";
661 }
662 } else {
663 hmod = NULL;
664 }
665 DWORD len = FormatMessageA(flags,
666 hmod,
667 err_,
668 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
669 msgbuf,
670 sizeof(msgbuf) / sizeof(msgbuf[0]),
671 NULL);
672 if (len) {
673 while ((len > 0) &&
674 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
675 msgbuf[--len] = 0;
676 }
677 stream() << ": " << msgbuf;
678 } else {
679 stream() << ": Error " << GetLastError() << " while retrieving error "
680 << err_;
681 }
682}
683#elif defined(OS_POSIX)
684ErrnoLogMessage::ErrnoLogMessage(const char* file,
685 int line,
686 LogSeverity severity,
687 SystemErrorCode err)
688 : err_(err),
689 log_message_(file, line, severity) {
690}
691
692ErrnoLogMessage::~ErrnoLogMessage() {
693 stream() << ": " << safe_strerror(err_);
694}
695#endif // OS_WIN
696
initial.commitd7cae122008-07-26 21:49:38697void CloseLogFile() {
698 if (!log_file)
699 return;
700
[email protected]f6abeba2008-08-08 13:27:28701 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38702 log_file = NULL;
703}
704
[email protected]e36ddc82009-12-08 04:22:50705void RawLog(int level, const char* message) {
706 if (level >= min_log_level) {
707 size_t bytes_written = 0;
708 const size_t message_len = strlen(message);
709 int rv;
710 while (bytes_written < message_len) {
711 rv = HANDLE_EINTR(
712 write(STDERR_FILENO, message + bytes_written,
713 message_len - bytes_written));
714 if (rv < 0) {
715 // Give up, nothing we can do now.
716 break;
717 }
718 bytes_written += rv;
719 }
720
721 if (message_len > 0 && message[message_len - 1] != '\n') {
722 do {
723 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
724 if (rv < 0) {
725 // Give up, nothing we can do now.
726 break;
727 }
728 } while (rv != 1);
729 }
730 }
731
732 if (level == LOG_FATAL)
733 DebugUtil::BreakDebugger();
734}
735
[email protected]96fd0032009-04-24 00:13:08736} // namespace logging
initial.commitd7cae122008-07-26 21:49:38737
738std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
[email protected]047a03f2009-10-07 02:10:20739 return out << WideToUTF8(std::wstring(wstr));
initial.commitd7cae122008-07-26 21:49:38740}