blob: 1212fd23d558aacd5cf1161135609db90c01b1b7 [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
[email protected]e43eddf12009-12-29 00:32:52233#if defined(OS_POSIX) && !defined(OS_MACOSX)
[email protected]4883a4e2009-06-06 19:59:36234int GetLoggingFileDescriptor() {
235 // No locking needed, since this is only called by the zygote server,
236 // which is single-threaded.
237 if (log_file)
238 return fileno(log_file);
239 return -1;
240}
241#endif
242
initial.commitd7cae122008-07-26 21:49:38243void InitLogMutex() {
[email protected]f6abeba2008-08-08 13:27:28244#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38245 if (!log_mutex) {
246 // \ is not a legal character in mutex names so we replace \ with /
[email protected]614e9fa2008-08-11 22:52:59247 std::wstring safe_name(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38248 std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
249 std::wstring t(L"Global\\");
250 t.append(safe_name);
251 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
252 }
[email protected]f6abeba2008-08-08 13:27:28253#elif defined(OS_POSIX)
254 // statically initialized
255#endif
initial.commitd7cae122008-07-26 21:49:38256}
257
[email protected]f6abeba2008-08-08 13:27:28258void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
initial.commitd7cae122008-07-26 21:49:38259 LogLockingState lock_log, OldFileDeletionState delete_old) {
[email protected]bb975362009-01-21 01:00:22260 g_enable_dcheck =
261 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
initial.commitd7cae122008-07-26 21:49:38262
263 if (log_file) {
264 // calling InitLogging twice or after some log call has already opened the
265 // default log file will re-initialize to the new options
[email protected]f6abeba2008-08-08 13:27:28266 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38267 log_file = NULL;
268 }
269
270 lock_log_file = lock_log;
271 logging_destination = logging_dest;
272
273 // ignore file options if logging is disabled or only to system
274 if (logging_destination == LOG_NONE ||
275 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
276 return;
277
[email protected]614e9fa2008-08-11 22:52:59278 if (!log_file_name)
279 log_file_name = new PathString();
280 *log_file_name = new_log_file;
initial.commitd7cae122008-07-26 21:49:38281 if (delete_old == DELETE_OLD_LOG_FILE)
[email protected]614e9fa2008-08-11 22:52:59282 DeleteFilePath(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38283
284 if (lock_log_file == LOCK_LOG_FILE) {
285 InitLogMutex();
286 } else if (!log_lock) {
287 log_lock = new LockImpl();
288 }
289
290 InitializeLogFileHandle();
291}
292
293void SetMinLogLevel(int level) {
294 min_log_level = level;
295}
296
297int GetMinLogLevel() {
298 return min_log_level;
299}
300
301void SetLogFilterPrefix(const char* filter) {
302 if (log_filter_prefix) {
[email protected]614e9fa2008-08-11 22:52:59303 delete log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:38304 log_filter_prefix = NULL;
305 }
306
[email protected]614e9fa2008-08-11 22:52:59307 if (filter)
308 log_filter_prefix = new std::string(filter);
initial.commitd7cae122008-07-26 21:49:38309}
310
311void SetLogItems(bool enable_process_id, bool enable_thread_id,
312 bool enable_timestamp, bool enable_tickcount) {
313 log_process_id = enable_process_id;
314 log_thread_id = enable_thread_id;
315 log_timestamp = enable_timestamp;
316 log_tickcount = enable_tickcount;
317}
318
319void SetLogAssertHandler(LogAssertHandlerFunction handler) {
320 log_assert_handler = handler;
321}
322
[email protected]fb62a532009-02-12 01:19:05323void SetLogReportHandler(LogReportHandlerFunction handler) {
324 log_report_handler = handler;
325}
326
[email protected]2b07b8412009-11-25 15:26:34327void SetLogMessageHandler(LogMessageHandlerFunction handler) {
328 log_message_handler = handler;
329}
330
331
[email protected]d81baca42010-03-01 13:10:22332// Displays a message box to the user with the error message in it.
333// Used for fatal messages, where we close the app simultaneously.
334void DisplayDebugMessageInDialog(const std::string& str) {
initial.commitd7cae122008-07-26 21:49:38335 if (str.empty())
336 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]d81baca42010-03-01 13:10:22371#elif defined(USE_X11)
372 // 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
471 std::string str_newline(stream_.str());
[email protected]1d8c2702008-08-19 23:39:32472#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38473 str_newline.append("\r\n");
[email protected]1d8c2702008-08-19 23:39:32474#else
475 str_newline.append("\n");
476#endif
[email protected]2b07b8412009-11-25 15:26:34477 // Give any log message handler first dibs on the message.
478 if (log_message_handler && log_message_handler(severity_, str_newline))
479 return;
initial.commitd7cae122008-07-26 21:49:38480
481 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
[email protected]614e9fa2008-08-11 22:52:59482 str_newline.compare(message_start_, log_filter_prefix->size(),
483 log_filter_prefix->data()) != 0) {
initial.commitd7cae122008-07-26 21:49:38484 return;
485 }
486
487 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
[email protected]f6abeba2008-08-08 13:27:28488 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
489#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38490 OutputDebugStringA(str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02491 if (severity_ >= kAlwaysPrintErrorLevel) {
492#else
493 {
[email protected]107bc0f12008-08-26 17:48:18494#endif
[email protected]1ce41052009-12-02 00:34:02495 // TODO(erikkay): this interferes with the layout tests since it grabs
496 // stderr and stdout and diffs them against known data. Our info and warn
497 // logs add noise to that. Ideally, the layout tests would set the log
498 // level to ignore anything below error. When that happens, we should
499 // take this fprintf out of the #else so that Windows users can benefit
500 // from the output when running tests from the command-line. In the
501 // meantime, we leave this in for Mac and Linux, but until this is fixed
502 // they won't be able to pass any layout tests that have info or warn
503 // logs. See http://b/1343647
504 fprintf(stderr, "%s", str_newline.c_str());
505 fflush(stderr);
506 }
[email protected]a33c9892008-08-25 20:10:31507 } else if (severity_ >= kAlwaysPrintErrorLevel) {
508 // When we're only outputting to a log file, above a certain log level, we
509 // should still output to stderr so that we can better detect and diagnose
510 // problems with unit tests, especially on the buildbots.
511 fprintf(stderr, "%s", str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02512 fflush(stderr);
[email protected]f6abeba2008-08-08 13:27:28513 }
[email protected]52a261f2009-03-03 15:01:12514
initial.commitd7cae122008-07-26 21:49:38515 // write to log file
516 if (logging_destination != LOG_NONE &&
517 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
518 InitializeLogFileHandle()) {
[email protected]52a261f2009-03-03 15:01:12519 // We can have multiple threads and/or processes, so try to prevent them
520 // from clobbering each other's writes.
initial.commitd7cae122008-07-26 21:49:38521 if (lock_log_file == LOCK_LOG_FILE) {
522 // Ensure that the mutex is initialized in case the client app did not
[email protected]52a261f2009-03-03 15:01:12523 // call InitLogging. This is not thread safe. See below.
initial.commitd7cae122008-07-26 21:49:38524 InitLogMutex();
525
[email protected]f6abeba2008-08-08 13:27:28526#if defined(OS_WIN)
[email protected]c0e27152009-08-03 18:35:53527 ::WaitForSingleObject(log_mutex, INFINITE);
528 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
529 // abort the process here. UI tests might be crashy sometimes,
530 // and aborting the test binary only makes the problem worse.
531 // We also don't use LOG macros because that might lead to an infinite
532 // loop. For more info see http://crbug.com/18028.
[email protected]f6abeba2008-08-08 13:27:28533#elif defined(OS_POSIX)
534 pthread_mutex_lock(&log_mutex);
535#endif
initial.commitd7cae122008-07-26 21:49:38536 } else {
537 // use the lock
538 if (!log_lock) {
539 // The client app did not call InitLogging, and so the lock has not
540 // been created. We do this on demand, but if two threads try to do
541 // this at the same time, there will be a race condition to create
542 // the lock. This is why InitLogging should be called from the main
543 // thread at the beginning of execution.
544 log_lock = new LockImpl();
545 }
546 log_lock->Lock();
547 }
548
[email protected]f6abeba2008-08-08 13:27:28549#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38550 SetFilePointer(log_file, 0, 0, SEEK_END);
551 DWORD num_written;
[email protected]52a261f2009-03-03 15:01:12552 WriteFile(log_file,
[email protected]5982f1f32009-03-03 15:10:58553 static_cast<const void*>(str_newline.c_str()),
[email protected]52a261f2009-03-03 15:01:12554 static_cast<DWORD>(str_newline.length()),
555 &num_written,
556 NULL);
[email protected]f6abeba2008-08-08 13:27:28557#else
558 fprintf(log_file, "%s", str_newline.c_str());
[email protected]1ce41052009-12-02 00:34:02559 fflush(log_file);
[email protected]f6abeba2008-08-08 13:27:28560#endif
initial.commitd7cae122008-07-26 21:49:38561
562 if (lock_log_file == LOCK_LOG_FILE) {
[email protected]f6abeba2008-08-08 13:27:28563#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38564 ReleaseMutex(log_mutex);
[email protected]f6abeba2008-08-08 13:27:28565#elif defined(OS_POSIX)
566 pthread_mutex_unlock(&log_mutex);
567#endif
initial.commitd7cae122008-07-26 21:49:38568 } else {
569 log_lock->Unlock();
570 }
571 }
572
573 if (severity_ == LOG_FATAL) {
574 // display a message or break into the debugger on a fatal error
[email protected]1ffe08c12008-08-13 11:15:11575 if (DebugUtil::BeingDebugged()) {
576 DebugUtil::BreakDebugger();
577 } else {
[email protected]96fd0032009-04-24 00:13:08578#ifndef NDEBUG
579 // Dump a stack trace on a fatal.
580 StackTrace trace;
581 stream_ << "\n"; // Newline to separate from log message.
582 trace.OutputToStream(&stream_);
583#endif
584
initial.commitd7cae122008-07-26 21:49:38585 if (log_assert_handler) {
586 // make a copy of the string for the handler out of paranoia
587 log_assert_handler(std::string(stream_.str()));
588 } else {
[email protected]4d5901272008-11-06 00:33:50589 // Don't use the string with the newline, get a fresh version to send to
590 // the debug message process. We also don't display assertions to the
591 // user in release mode. The enduser can't do anything with this
592 // information, and displaying message boxes when the application is
593 // hosed can cause additional problems.
594#ifndef NDEBUG
[email protected]d81baca42010-03-01 13:10:22595 DisplayDebugMessageInDialog(stream_.str());
[email protected]4d5901272008-11-06 00:33:50596#endif
initial.commitd7cae122008-07-26 21:49:38597 // Crash the process to generate a dump.
[email protected]1ffe08c12008-08-13 11:15:11598 DebugUtil::BreakDebugger();
initial.commitd7cae122008-07-26 21:49:38599 }
600 }
[email protected]fb62a532009-02-12 01:19:05601 } else if (severity_ == LOG_ERROR_REPORT) {
602 // We are here only if the user runs with --enable-dcheck in release mode.
603 if (log_report_handler) {
604 log_report_handler(std::string(stream_.str()));
605 } else {
[email protected]d81baca42010-03-01 13:10:22606 DisplayDebugMessageInDialog(stream_.str());
[email protected]fb62a532009-02-12 01:19:05607 }
initial.commitd7cae122008-07-26 21:49:38608 }
609}
610
[email protected]d8617a62009-10-09 23:52:20611#if defined(OS_WIN)
612// This has already been defined in the header, but defining it again as DWORD
613// ensures that the type used in the header is equivalent to DWORD. If not,
614// the redefinition is a compile error.
615typedef DWORD SystemErrorCode;
616#endif
617
618SystemErrorCode GetLastSystemErrorCode() {
619#if defined(OS_WIN)
620 return ::GetLastError();
621#elif defined(OS_POSIX)
622 return errno;
623#else
624#error Not implemented
625#endif
626}
627
628#if defined(OS_WIN)
629Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
630 int line,
631 LogSeverity severity,
632 SystemErrorCode err,
633 const char* module)
634 : err_(err),
635 module_(module),
636 log_message_(file, line, severity) {
637}
638
639Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
640 int line,
641 LogSeverity severity,
642 SystemErrorCode err)
643 : err_(err),
644 module_(NULL),
645 log_message_(file, line, severity) {
646}
647
648Win32ErrorLogMessage::~Win32ErrorLogMessage() {
649 const int error_message_buffer_size = 256;
650 char msgbuf[error_message_buffer_size];
651 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
652 HMODULE hmod;
653 if (module_) {
654 hmod = GetModuleHandleA(module_);
655 if (hmod) {
656 flags |= FORMAT_MESSAGE_FROM_HMODULE;
657 } else {
658 // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
659 // so it will not call GetModuleHandle, so recursive errors are
660 // impossible.
661 DPLOG(WARNING) << "Couldn't open module " << module_
662 << " for error message query";
663 }
664 } else {
665 hmod = NULL;
666 }
667 DWORD len = FormatMessageA(flags,
668 hmod,
669 err_,
670 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
671 msgbuf,
672 sizeof(msgbuf) / sizeof(msgbuf[0]),
673 NULL);
674 if (len) {
675 while ((len > 0) &&
676 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
677 msgbuf[--len] = 0;
678 }
679 stream() << ": " << msgbuf;
680 } else {
681 stream() << ": Error " << GetLastError() << " while retrieving error "
682 << err_;
683 }
684}
685#elif defined(OS_POSIX)
686ErrnoLogMessage::ErrnoLogMessage(const char* file,
687 int line,
688 LogSeverity severity,
689 SystemErrorCode err)
690 : err_(err),
691 log_message_(file, line, severity) {
692}
693
694ErrnoLogMessage::~ErrnoLogMessage() {
695 stream() << ": " << safe_strerror(err_);
696}
697#endif // OS_WIN
698
initial.commitd7cae122008-07-26 21:49:38699void CloseLogFile() {
700 if (!log_file)
701 return;
702
[email protected]f6abeba2008-08-08 13:27:28703 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38704 log_file = NULL;
705}
706
[email protected]e36ddc82009-12-08 04:22:50707void RawLog(int level, const char* message) {
708 if (level >= min_log_level) {
709 size_t bytes_written = 0;
710 const size_t message_len = strlen(message);
711 int rv;
712 while (bytes_written < message_len) {
713 rv = HANDLE_EINTR(
714 write(STDERR_FILENO, message + bytes_written,
715 message_len - bytes_written));
716 if (rv < 0) {
717 // Give up, nothing we can do now.
718 break;
719 }
720 bytes_written += rv;
721 }
722
723 if (message_len > 0 && message[message_len - 1] != '\n') {
724 do {
725 rv = HANDLE_EINTR(write(STDERR_FILENO, "\n", 1));
726 if (rv < 0) {
727 // Give up, nothing we can do now.
728 break;
729 }
730 } while (rv != 1);
731 }
732 }
733
734 if (level == LOG_FATAL)
735 DebugUtil::BreakDebugger();
736}
737
[email protected]96fd0032009-04-24 00:13:08738} // namespace logging
initial.commitd7cae122008-07-26 21:49:38739
740std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
[email protected]047a03f2009-10-07 02:10:20741 return out << WideToUTF8(std::wstring(wstr));
initial.commitd7cae122008-07-26 21:49:38742}