blob: 09decbbaca471092ef7201cf7ebec67d887462fa [file] [log] [blame]
[email protected]96fd0032009-04-24 00:13:081// Copyright (c) 2006-2009 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]f6abeba2008-08-08 13:27:2828#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
initial.commitd7cae122008-07-26 21:49:3837#include <ctime>
38#include <iomanip>
39#include <cstring>
initial.commitd7cae122008-07-26 21:49:3840#include <algorithm>
[email protected]b16ef312008-08-19 18:36:2341
initial.commitd7cae122008-07-26 21:49:3842#include "base/base_switches.h"
43#include "base/command_line.h"
[email protected]1ffe08c12008-08-13 11:15:1144#include "base/debug_util.h"
[email protected]e36ddc82009-12-08 04:22:5045#include "base/eintr_wrapper.h"
initial.commitd7cae122008-07-26 21:49:3846#include "base/lock_impl.h"
[email protected]d8617a62009-10-09 23:52:2047#if defined(OS_POSIX)
48#include "base/safe_strerror_posix.h"
49#endif
[email protected]d81baca42010-03-01 13:10:2250#include "base/process_util.h"
[email protected]4bdaceb42008-08-19 13:19:2451#include "base/string_piece.h"
[email protected]f6abeba2008-08-08 13:27:2852#include "base/string_util.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;
63LogLockingState 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)
85typedef wchar_t PathChar;
[email protected]614e9fa2008-08-11 22:52:5986typedef std::wstring PathString;
[email protected]f6abeba2008-08-08 13:27:2887#else
88typedef char PathChar;
[email protected]614e9fa2008-08-11 22:52:5989typedef std::string PathString;
[email protected]f6abeba2008-08-08 13:27:2890#endif
[email protected]614e9fa2008-08-11 22:52:5991PathString* log_file_name = NULL;
initial.commitd7cae122008-07-26 21:49:3892
93// this file is lazily opened and the handle may be NULL
[email protected]f6abeba2008-08-08 13:27:2894FileHandle log_file = NULL;
initial.commitd7cae122008-07-26 21:49:3895
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
[email protected]fb62a532009-02-12 01:19:05103// the debug message dialog and process termination.
initial.commitd7cae122008-07-26 21:49:38104LogAssertHandlerFunction log_assert_handler = NULL;
[email protected]fb62a532009-02-12 01:19:05105// An report handler override specified by the client to be called instead of
106// the debug message dialog.
107LogReportHandlerFunction log_report_handler = NULL;
[email protected]2b07b8412009-11-25 15:26:34108// A log message handler that gets notified of every log message we process.
109LogMessageHandlerFunction log_message_handler = NULL;
initial.commitd7cae122008-07-26 21:49:38110
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.
[email protected]f6abeba2008-08-08 13:27:28118#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
[email protected]f8588472008-11-05 23:17:24126int32 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();
[email protected]052f1b52008-11-06 21:43:07139#elif defined(OS_LINUX)
140 return syscall(__NR_gettid);
[email protected]e43eddf12009-12-29 00:32:52141#elif defined(OS_FREEBSD)
142 // TODO(BSD): find a better thread ID
143 return reinterpret_cast<int64>(pthread_self());
[email protected]f8588472008-11-05 23:17:24144#endif
145}
146
147uint64 TickCount() {
148#if defined(OS_WIN)
149 return GetTickCount();
150#elif defined(OS_MACOSX)
151 return mach_absolute_time();
[email protected]e43eddf12009-12-29 00:32:52152#elif defined(OS_POSIX)
[email protected]052f1b52008-11-06 21:43:07153 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;
[email protected]f8588472008-11-05 23:17:24161#endif
162}
163
[email protected]f6abeba2008-08-08 13:27:28164void CloseFile(FileHandle log) {
165#if defined(OS_WIN)
166 CloseHandle(log);
167#else
168 fclose(log);
169#endif
170}
171
[email protected]614e9fa2008-08-11 22:52:59172void DeleteFilePath(const PathString& log_name) {
[email protected]f6abeba2008-08-08 13:27:28173#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:59174 DeleteFile(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28175#else
[email protected]614e9fa2008-08-11 22:52:59176 unlink(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28177#endif
178}
initial.commitd7cae122008-07-26 21:49:38179
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
[email protected]614e9fa2008-08-11 22:52:59187 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.
[email protected]f6abeba2008-08-08 13:27:28190#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:59191 // 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
initial.commitd7cae122008-07-26 21:49:38204 }
205
[email protected]1d8c2702008-08-19 23:39:32206 if (logging_destination == LOG_ONLY_TO_FILE ||
207 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
[email protected]614e9fa2008-08-11 22:52:59208#if defined(OS_WIN)
[email protected]1d8c2702008-08-19 23:39:32209 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
initial.commitd7cae122008-07-26 21:49:38210 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
211 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
212 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
[email protected]1d8c2702008-08-19 23:39:32213 // 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 }
initial.commitd7cae122008-07-26 21:49:38221 }
[email protected]1d8c2702008-08-19 23:39:32222 SetFilePointer(log_file, 0, 0, FILE_END);
[email protected]78c6dd62009-06-08 23:29:11223#elif defined(OS_POSIX)
224 log_file = fopen(log_file_name->c_str(), "a");
225 if (log_file == NULL)
226 return false;
[email protected]f6abeba2008-08-08 13:27:28227#endif
[email protected]1d8c2702008-08-19 23:39:32228 }
229
initial.commitd7cae122008-07-26 21:49:38230 return true;
231}
232
233void InitLogMutex() {
[email protected]f6abeba2008-08-08 13:27:28234#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38235 if (!log_mutex) {
236 // \ is not a legal character in mutex names so we replace \ with /
[email protected]614e9fa2008-08-11 22:52:59237 std::wstring safe_name(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38238 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 }
[email protected]f6abeba2008-08-08 13:27:28243#elif defined(OS_POSIX)
244 // statically initialized
245#endif
initial.commitd7cae122008-07-26 21:49:38246}
247
[email protected]f6abeba2008-08-08 13:27:28248void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
initial.commitd7cae122008-07-26 21:49:38249 LogLockingState lock_log, OldFileDeletionState delete_old) {
[email protected]bb975362009-01-21 01:00:22250 g_enable_dcheck =
251 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
initial.commitd7cae122008-07-26 21:49:38252
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
[email protected]f6abeba2008-08-08 13:27:28256 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38257 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
[email protected]614e9fa2008-08-11 22:52:59268 if (!log_file_name)
269 log_file_name = new PathString();
270 *log_file_name = new_log_file;
initial.commitd7cae122008-07-26 21:49:38271 if (delete_old == DELETE_OLD_LOG_FILE)
[email protected]614e9fa2008-08-11 22:52:59272 DeleteFilePath(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38273
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) {
[email protected]614e9fa2008-08-11 22:52:59293 delete log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:38294 log_filter_prefix = NULL;
295 }
296
[email protected]614e9fa2008-08-11 22:52:59297 if (filter)
298 log_filter_prefix = new std::string(filter);
initial.commitd7cae122008-07-26 21:49:38299}
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
[email protected]fb62a532009-02-12 01:19:05313void SetLogReportHandler(LogReportHandlerFunction handler) {
314 log_report_handler = handler;
315}
316
[email protected]2b07b8412009-11-25 15:26:34317void SetLogMessageHandler(LogMessageHandlerFunction handler) {
318 log_message_handler = handler;
319}
320
321
[email protected]d81baca42010-03-01 13:10:22322// 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) {
initial.commitd7cae122008-07-26 21:49:38325 if (str.empty())
326 return;
327
[email protected]846ed9c32010-07-29 20:33:44328 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoErrorDialogs))
329 return;
330
[email protected]f6abeba2008-08-08 13:27:28331#if defined(OS_WIN)
[email protected]d81baca42010-03-01 13:10:22332 // For Windows programs, it's possible that the message loop is
333 // messed up on a fatal error, and creating a MessageBox will cause
334 // that message loop to be run. Instead, we try to spawn another
335 // process that displays its command line. We look for "Debug
336 // Message.exe" in the same directory as the application. If it
337 // exists, we use it, otherwise, we use a regular message box.
initial.commitd7cae122008-07-26 21:49:38338 wchar_t prog_name[MAX_PATH];
339 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
340 wchar_t* backslash = wcsrchr(prog_name, '\\');
341 if (backslash)
342 backslash[1] = 0;
343 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
344
[email protected]047a03f2009-10-07 02:10:20345 std::wstring cmdline = UTF8ToWide(str);
[email protected]3ca4214c12009-03-25 22:12:02346 if (cmdline.empty())
347 return;
initial.commitd7cae122008-07-26 21:49:38348
349 STARTUPINFO startup_info;
350 memset(&startup_info, 0, sizeof(startup_info));
351 startup_info.cb = sizeof(startup_info);
352
353 PROCESS_INFORMATION process_info;
[email protected]3ca4214c12009-03-25 22:12:02354 if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
initial.commitd7cae122008-07-26 21:49:38355 NULL, &startup_info, &process_info)) {
356 WaitForSingleObject(process_info.hProcess, INFINITE);
357 CloseHandle(process_info.hThread);
358 CloseHandle(process_info.hProcess);
359 } else {
360 // debug process broken, let's just do a message box
[email protected]3ca4214c12009-03-25 22:12:02361 MessageBoxW(NULL, &cmdline[0], L"Fatal error",
initial.commitd7cae122008-07-26 21:49:38362 MB_OK | MB_ICONHAND | MB_TOPMOST);
363 }
[email protected]d81baca42010-03-01 13:10:22364#elif defined(USE_X11)
365 // Shell out to xmessage, which behaves like debug_message.exe, but is
366 // way more retro. We could use zenity/kdialog but then we're starting
367 // to get into needing to check the desktop env and this dialog should
368 // only be coming up in Very Bad situations.
369 std::vector<std::string> argv;
370 argv.push_back("xmessage");
371 argv.push_back(str);
372 base::LaunchApp(argv, base::file_handle_mapping_vector(), true /* wait */,
373 NULL);
[email protected]f6abeba2008-08-08 13:27:28374#else
[email protected]d81baca42010-03-01 13:10:22375 // http://code.google.com/p/chromium/issues/detail?id=37026
376 NOTIMPLEMENTED();
[email protected]f6abeba2008-08-08 13:27:28377#endif
initial.commitd7cae122008-07-26 21:49:38378}
379
[email protected]3f85caa2009-04-14 16:52:11380#if defined(OS_WIN)
381LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
382}
383
384LogMessage::SaveLastError::~SaveLastError() {
385 ::SetLastError(last_error_);
386}
387#endif // defined(OS_WIN)
388
initial.commitd7cae122008-07-26 21:49:38389LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
390 int ctr)
391 : severity_(severity) {
392 Init(file, line);
393}
394
395LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
396 : severity_(LOG_FATAL) {
397 Init(file, line);
398 stream_ << "Check failed: " << (*result.str_);
399}
400
[email protected]fb62a532009-02-12 01:19:05401LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
402 const CheckOpString& result)
403 : severity_(severity) {
404 Init(file, line);
405 stream_ << "Check failed: " << (*result.str_);
406}
407
initial.commitd7cae122008-07-26 21:49:38408LogMessage::LogMessage(const char* file, int line)
409 : severity_(LOG_INFO) {
410 Init(file, line);
411}
412
413LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
414 : severity_(severity) {
415 Init(file, line);
416}
417
418// writes the common header info to the stream
419void LogMessage::Init(const char* file, int line) {
420 // log only the filename
421 const char* last_slash = strrchr(file, '\\');
422 if (last_slash)
423 file = last_slash + 1;
424
425 // TODO(darin): It might be nice if the columns were fixed width.
426
427 stream_ << '[';
428 if (log_process_id)
[email protected]f8588472008-11-05 23:17:24429 stream_ << CurrentProcessId() << ':';
initial.commitd7cae122008-07-26 21:49:38430 if (log_thread_id)
[email protected]f8588472008-11-05 23:17:24431 stream_ << CurrentThreadId() << ':';
initial.commitd7cae122008-07-26 21:49:38432 if (log_timestamp) {
[email protected]defcd8f32009-05-13 00:03:43433 time_t t = time(NULL);
initial.commitd7cae122008-07-26 21:49:38434 struct tm local_time = {0};
[email protected]defcd8f32009-05-13 00:03:43435#if _MSC_VER >= 1400
initial.commitd7cae122008-07-26 21:49:38436 localtime_s(&local_time, &t);
initial.commitd7cae122008-07-26 21:49:38437#else
[email protected]defcd8f32009-05-13 00:03:43438 localtime_r(&t, &local_time);
initial.commitd7cae122008-07-26 21:49:38439#endif
[email protected]defcd8f32009-05-13 00:03:43440 struct tm* tm_time = &local_time;
initial.commitd7cae122008-07-26 21:49:38441 stream_ << std::setfill('0')
442 << std::setw(2) << 1 + tm_time->tm_mon
443 << std::setw(2) << tm_time->tm_mday
444 << '/'
445 << std::setw(2) << tm_time->tm_hour
446 << std::setw(2) << tm_time->tm_min
447 << std::setw(2) << tm_time->tm_sec
448 << ':';
449 }
450 if (log_tickcount)
[email protected]f8588472008-11-05 23:17:24451 stream_ << TickCount() << ':';
[email protected]52a261f2009-03-03 15:01:12452 stream_ << log_severity_names[severity_] << ":" << file <<
453 "(" << line << ")] ";
initial.commitd7cae122008-07-26 21:49:38454
455 message_start_ = stream_.tellp();
456}
457
458LogMessage::~LogMessage() {
459 // TODO(brettw) modify the macros so that nothing is executed when the log
460 // level is too high.
461 if (severity_ < min_log_level)
462 return;
463
[email protected]d1ccc35a2010-03-24 05:03:24464#ifndef NDEBUG
465 if (severity_ == LOG_FATAL) {
466 // Include a stack trace on a fatal.
467 StackTrace trace;
468 stream_ << std::endl; // Newline to separate from log message.
469 trace.OutputToStream(&stream_);
470 }
[email protected]1d8c2702008-08-19 23:39:32471#endif
[email protected]d1ccc35a2010-03-24 05:03:24472 stream_ << std::endl;
473 std::string str_newline(stream_.str());
474
[email protected]2b07b8412009-11-25 15:26:34475 // Give any log message handler first dibs on the message.
476 if (log_message_handler && log_message_handler(severity_, str_newline))
477 return;
initial.commitd7cae122008-07-26 21:49:38478
479 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
[email protected]614e9fa2008-08-11 22:52:59480 str_newline.compare(message_start_, log_filter_prefix->size(),
481 log_filter_prefix->data()) != 0) {
initial.commitd7cae122008-07-26 21:49:38482 return;
483 }
484
485 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
[email protected]f6abeba2008-08-08 13:27:28486 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
487#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38488 OutputDebugStringA(str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02489 if (severity_ >= kAlwaysPrintErrorLevel) {
490#else
491 {
[email protected]107bc0f12008-08-26 17:48:18492#endif
[email protected]1ce41052009-12-02 00:34:02493 // TODO(erikkay): this interferes with the layout tests since it grabs
494 // stderr and stdout and diffs them against known data. Our info and warn
495 // logs add noise to that. Ideally, the layout tests would set the log
496 // level to ignore anything below error. When that happens, we should
497 // take this fprintf out of the #else so that Windows users can benefit
498 // from the output when running tests from the command-line. In the
499 // meantime, we leave this in for Mac and Linux, but until this is fixed
500 // they won't be able to pass any layout tests that have info or warn
501 // logs. See http://b/1343647
502 fprintf(stderr, "%s", str_newline.c_str());
503 fflush(stderr);
504 }
[email protected]a33c9892008-08-25 20:10:31505 } else if (severity_ >= kAlwaysPrintErrorLevel) {
506 // When we're only outputting to a log file, above a certain log level, we
507 // should still output to stderr so that we can better detect and diagnose
508 // problems with unit tests, especially on the buildbots.
509 fprintf(stderr, "%s", str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02510 fflush(stderr);
[email protected]f6abeba2008-08-08 13:27:28511 }
[email protected]52a261f2009-03-03 15:01:12512
initial.commitd7cae122008-07-26 21:49:38513 // write to log file
514 if (logging_destination != LOG_NONE &&
515 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
516 InitializeLogFileHandle()) {
[email protected]52a261f2009-03-03 15:01:12517 // We can have multiple threads and/or processes, so try to prevent them
518 // from clobbering each other's writes.
initial.commitd7cae122008-07-26 21:49:38519 if (lock_log_file == LOCK_LOG_FILE) {
520 // Ensure that the mutex is initialized in case the client app did not
[email protected]52a261f2009-03-03 15:01:12521 // call InitLogging. This is not thread safe. See below.
initial.commitd7cae122008-07-26 21:49:38522 InitLogMutex();
523
[email protected]f6abeba2008-08-08 13:27:28524#if defined(OS_WIN)
[email protected]c0e27152009-08-03 18:35:53525 ::WaitForSingleObject(log_mutex, INFINITE);
526 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
527 // abort the process here. UI tests might be crashy sometimes,
528 // and aborting the test binary only makes the problem worse.
529 // We also don't use LOG macros because that might lead to an infinite
530 // loop. For more info see http://crbug.com/18028.
[email protected]f6abeba2008-08-08 13:27:28531#elif defined(OS_POSIX)
532 pthread_mutex_lock(&log_mutex);
533#endif
initial.commitd7cae122008-07-26 21:49:38534 } else {
535 // use the lock
536 if (!log_lock) {
537 // The client app did not call InitLogging, and so the lock has not
538 // been created. We do this on demand, but if two threads try to do
539 // this at the same time, there will be a race condition to create
540 // the lock. This is why InitLogging should be called from the main
541 // thread at the beginning of execution.
542 log_lock = new LockImpl();
543 }
544 log_lock->Lock();
545 }
546
[email protected]f6abeba2008-08-08 13:27:28547#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38548 SetFilePointer(log_file, 0, 0, SEEK_END);
549 DWORD num_written;
[email protected]52a261f2009-03-03 15:01:12550 WriteFile(log_file,
[email protected]5982f1f32009-03-03 15:10:58551 static_cast<const void*>(str_newline.c_str()),
[email protected]52a261f2009-03-03 15:01:12552 static_cast<DWORD>(str_newline.length()),
553 &num_written,
554 NULL);
[email protected]f6abeba2008-08-08 13:27:28555#else
556 fprintf(log_file, "%s", str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02557 fflush(log_file);
[email protected]f6abeba2008-08-08 13:27:28558#endif
initial.commitd7cae122008-07-26 21:49:38559
560 if (lock_log_file == LOCK_LOG_FILE) {
[email protected]f6abeba2008-08-08 13:27:28561#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38562 ReleaseMutex(log_mutex);
[email protected]f6abeba2008-08-08 13:27:28563#elif defined(OS_POSIX)
564 pthread_mutex_unlock(&log_mutex);
565#endif
initial.commitd7cae122008-07-26 21:49:38566 } else {
567 log_lock->Unlock();
568 }
569 }
570
571 if (severity_ == LOG_FATAL) {
572 // display a message or break into the debugger on a fatal error
[email protected]1ffe08c12008-08-13 11:15:11573 if (DebugUtil::BeingDebugged()) {
574 DebugUtil::BreakDebugger();
575 } else {
initial.commitd7cae122008-07-26 21:49:38576 if (log_assert_handler) {
577 // make a copy of the string for the handler out of paranoia
578 log_assert_handler(std::string(stream_.str()));
579 } else {
[email protected]4d5901272008-11-06 00:33:50580 // Don't use the string with the newline, get a fresh version to send to
581 // the debug message process. We also don't display assertions to the
582 // user in release mode. The enduser can't do anything with this
583 // information, and displaying message boxes when the application is
584 // hosed can cause additional problems.
585#ifndef NDEBUG
[email protected]d81baca42010-03-01 13:10:22586 DisplayDebugMessageInDialog(stream_.str());
[email protected]4d5901272008-11-06 00:33:50587#endif
initial.commitd7cae122008-07-26 21:49:38588 // Crash the process to generate a dump.
[email protected]1ffe08c12008-08-13 11:15:11589 DebugUtil::BreakDebugger();
initial.commitd7cae122008-07-26 21:49:38590 }
591 }
[email protected]fb62a532009-02-12 01:19:05592 } else if (severity_ == LOG_ERROR_REPORT) {
593 // We are here only if the user runs with --enable-dcheck in release mode.
594 if (log_report_handler) {
595 log_report_handler(std::string(stream_.str()));
596 } else {
[email protected]d81baca42010-03-01 13:10:22597 DisplayDebugMessageInDialog(stream_.str());
[email protected]fb62a532009-02-12 01:19:05598 }
initial.commitd7cae122008-07-26 21:49:38599 }
600}
601
[email protected]d8617a62009-10-09 23:52:20602#if defined(OS_WIN)
603// This has already been defined in the header, but defining it again as DWORD
604// ensures that the type used in the header is equivalent to DWORD. If not,
605// the redefinition is a compile error.
606typedef DWORD SystemErrorCode;
607#endif
608
609SystemErrorCode GetLastSystemErrorCode() {
610#if defined(OS_WIN)
611 return ::GetLastError();
612#elif defined(OS_POSIX)
613 return errno;
614#else
615#error Not implemented
616#endif
617}
618
619#if defined(OS_WIN)
620Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
621 int line,
622 LogSeverity severity,
623 SystemErrorCode err,
624 const char* module)
625 : err_(err),
626 module_(module),
627 log_message_(file, line, severity) {
628}
629
630Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
631 int line,
632 LogSeverity severity,
633 SystemErrorCode err)
634 : err_(err),
635 module_(NULL),
636 log_message_(file, line, severity) {
637}
638
639Win32ErrorLogMessage::~Win32ErrorLogMessage() {
640 const int error_message_buffer_size = 256;
641 char msgbuf[error_message_buffer_size];
642 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
643 HMODULE hmod;
644 if (module_) {
645 hmod = GetModuleHandleA(module_);
646 if (hmod) {
647 flags |= FORMAT_MESSAGE_FROM_HMODULE;
648 } else {
649 // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
650 // so it will not call GetModuleHandle, so recursive errors are
651 // impossible.
652 DPLOG(WARNING) << "Couldn't open module " << module_
653 << " for error message query";
654 }
655 } else {
656 hmod = NULL;
657 }
658 DWORD len = FormatMessageA(flags,
659 hmod,
660 err_,
661 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
662 msgbuf,
663 sizeof(msgbuf) / sizeof(msgbuf[0]),
664 NULL);
665 if (len) {
666 while ((len > 0) &&
667 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
668 msgbuf[--len] = 0;
669 }
670 stream() << ": " << msgbuf;
671 } else {
672 stream() << ": Error " << GetLastError() << " while retrieving error "
673 << err_;
674 }
675}
676#elif defined(OS_POSIX)
677ErrnoLogMessage::ErrnoLogMessage(const char* file,
678 int line,
679 LogSeverity severity,
680 SystemErrorCode err)
681 : err_(err),
682 log_message_(file, line, severity) {
683}
684
685ErrnoLogMessage::~ErrnoLogMessage() {
686 stream() << ": " << safe_strerror(err_);
687}
688#endif // OS_WIN
689
initial.commitd7cae122008-07-26 21:49:38690void CloseLogFile() {
691 if (!log_file)
692 return;
693
[email protected]f6abeba2008-08-08 13:27:28694 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38695 log_file = NULL;
696}
697
[email protected]e36ddc82009-12-08 04:22:50698void RawLog(int level, const char* message) {
699 if (level >= min_log_level) {
700 size_t bytes_written = 0;
701 const size_t message_len = strlen(message);
702 int rv;
703 while (bytes_written < message_len) {
704 rv = HANDLE_EINTR(
705 write(STDERR_FILENO, message + bytes_written,
706 message_len - bytes_written));
707 if (rv < 0) {
708 // Give up, nothing we can do now.
709 break;
710 }
711 bytes_written += rv;
712 }
713
714 if (message_len > 0 && message[message_len - 1] != '\n') {
715 do {
716 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
717 if (rv < 0) {
718 // Give up, nothing we can do now.
719 break;
720 }
721 } while (rv != 1);
722 }
723 }
724
725 if (level == LOG_FATAL)
726 DebugUtil::BreakDebugger();
727}
728
[email protected]96fd0032009-04-24 00:13:08729} // namespace logging
initial.commitd7cae122008-07-26 21:49:38730
731std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
[email protected]047a03f2009-10-07 02:10:20732 return out << WideToUTF8(std::wstring(wstr));
initial.commitd7cae122008-07-26 21:49:38733}