blob: 7420883a6f33c888fccbf44268b69004f954f9ea [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]f6abeba2008-08-08 13:27:288#include <windows.h>
9typedef HANDLE FileHandle;
10typedef HANDLE MutexHandle;
[email protected]052f1b52008-11-06 21:43:0711#elif defined(OS_MACOSX)
[email protected]f6abeba2008-08-08 13:27:2812#include <CoreFoundation/CoreFoundation.h>
13#include <mach/mach.h>
14#include <mach/mach_time.h>
15#include <mach-o/dyld.h>
[email protected]052f1b52008-11-06 21:43:0716#elif defined(OS_LINUX)
17#include <sys/syscall.h>
18#include <time.h>
[email protected]614e9fa2008-08-11 22:52:5919#endif
20
21#if defined(OS_POSIX)
[email protected]f6abeba2008-08-08 13:27:2822#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26#define MAX_PATH PATH_MAX
27typedef FILE* FileHandle;
28typedef pthread_mutex_t* MutexHandle;
29#endif
30
initial.commitd7cae122008-07-26 21:49:3831#include <ctime>
32#include <iomanip>
33#include <cstring>
initial.commitd7cae122008-07-26 21:49:3834#include <algorithm>
[email protected]b16ef312008-08-19 18:36:2335
initial.commitd7cae122008-07-26 21:49:3836#include "base/base_switches.h"
37#include "base/command_line.h"
[email protected]1ffe08c12008-08-13 11:15:1138#include "base/debug_util.h"
initial.commitd7cae122008-07-26 21:49:3839#include "base/lock_impl.h"
[email protected]4bdaceb42008-08-19 13:19:2440#include "base/string_piece.h"
[email protected]f6abeba2008-08-08 13:27:2841#include "base/string_util.h"
[email protected]15af80e2008-08-07 03:11:4242#include "base/sys_string_conversions.h"
[email protected]52a261f2009-03-03 15:01:1243
initial.commitd7cae122008-07-26 21:49:3844namespace logging {
45
46bool g_enable_dcheck = false;
47
48const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
[email protected]fb62a532009-02-12 01:19:0549 "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
initial.commitd7cae122008-07-26 21:49:3850
51int min_log_level = 0;
52LogLockingState lock_log_file = LOCK_LOG_FILE;
[email protected]1d8c2702008-08-19 23:39:3253
54// The default set here for logging_destination will only be used if
55// InitLogging is not called. On Windows, use a file next to the exe;
56// on POSIX platforms, where it may not even be possible to locate the
57// executable on disk, use stderr.
[email protected]4c0040c2008-08-15 01:04:1158#if defined(OS_WIN)
[email protected]fe613522008-08-22 17:09:3459LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
[email protected]4c0040c2008-08-15 01:04:1160#elif defined(OS_POSIX)
[email protected]1d8c2702008-08-19 23:39:3261LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
[email protected]4c0040c2008-08-15 01:04:1162#endif
initial.commitd7cae122008-07-26 21:49:3863
64const int kMaxFilteredLogLevel = LOG_WARNING;
[email protected]614e9fa2008-08-11 22:52:5965std::string* log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:3866
[email protected]a33c9892008-08-25 20:10:3167// For LOG_ERROR and above, always print to stderr.
68const int kAlwaysPrintErrorLevel = LOG_ERROR;
69
[email protected]614e9fa2008-08-11 22:52:5970// Which log file to use? This is initialized by InitLogging or
initial.commitd7cae122008-07-26 21:49:3871// will be lazily initialized to the default value when it is
72// first needed.
[email protected]f6abeba2008-08-08 13:27:2873#if defined(OS_WIN)
74typedef wchar_t PathChar;
[email protected]614e9fa2008-08-11 22:52:5975typedef std::wstring PathString;
[email protected]f6abeba2008-08-08 13:27:2876#else
77typedef char PathChar;
[email protected]614e9fa2008-08-11 22:52:5978typedef std::string PathString;
[email protected]f6abeba2008-08-08 13:27:2879#endif
[email protected]614e9fa2008-08-11 22:52:5980PathString* log_file_name = NULL;
initial.commitd7cae122008-07-26 21:49:3881
82// this file is lazily opened and the handle may be NULL
[email protected]f6abeba2008-08-08 13:27:2883FileHandle log_file = NULL;
initial.commitd7cae122008-07-26 21:49:3884
85// what should be prepended to each message?
86bool log_process_id = false;
87bool log_thread_id = false;
88bool log_timestamp = true;
89bool log_tickcount = false;
90
91// An assert handler override specified by the client to be called instead of
[email protected]fb62a532009-02-12 01:19:0592// the debug message dialog and process termination.
initial.commitd7cae122008-07-26 21:49:3893LogAssertHandlerFunction log_assert_handler = NULL;
[email protected]fb62a532009-02-12 01:19:0594// An report handler override specified by the client to be called instead of
95// the debug message dialog.
96LogReportHandlerFunction log_report_handler = NULL;
initial.commitd7cae122008-07-26 21:49:3897
98// The lock is used if log file locking is false. It helps us avoid problems
99// with multiple threads writing to the log file at the same time. Use
100// LockImpl directly instead of using Lock, because Lock makes logging calls.
101static LockImpl* log_lock = NULL;
102
103// When we don't use a lock, we are using a global mutex. We need to do this
104// because LockFileEx is not thread safe.
[email protected]f6abeba2008-08-08 13:27:28105#if defined(OS_WIN)
106MutexHandle log_mutex = NULL;
107#elif defined(OS_POSIX)
108pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
109#endif
110
111// Helper functions to wrap platform differences.
112
[email protected]f8588472008-11-05 23:17:24113int32 CurrentProcessId() {
114#if defined(OS_WIN)
115 return GetCurrentProcessId();
116#elif defined(OS_POSIX)
117 return getpid();
118#endif
119}
120
121int32 CurrentThreadId() {
122#if defined(OS_WIN)
123 return GetCurrentThreadId();
124#elif defined(OS_MACOSX)
125 return mach_thread_self();
[email protected]052f1b52008-11-06 21:43:07126#elif defined(OS_LINUX)
127 return syscall(__NR_gettid);
[email protected]f8588472008-11-05 23:17:24128#endif
129}
130
131uint64 TickCount() {
132#if defined(OS_WIN)
133 return GetTickCount();
134#elif defined(OS_MACOSX)
135 return mach_absolute_time();
[email protected]052f1b52008-11-06 21:43:07136#elif defined(OS_LINUX)
137 struct timespec ts;
138 clock_gettime(CLOCK_MONOTONIC, &ts);
139
140 uint64 absolute_micro =
141 static_cast<int64>(ts.tv_sec) * 1000000 +
142 static_cast<int64>(ts.tv_nsec) / 1000;
143
144 return absolute_micro;
[email protected]f8588472008-11-05 23:17:24145#endif
146}
147
[email protected]f6abeba2008-08-08 13:27:28148void CloseFile(FileHandle log) {
149#if defined(OS_WIN)
150 CloseHandle(log);
151#else
152 fclose(log);
153#endif
154}
155
[email protected]614e9fa2008-08-11 22:52:59156void DeleteFilePath(const PathString& log_name) {
[email protected]f6abeba2008-08-08 13:27:28157#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:59158 DeleteFile(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28159#else
[email protected]614e9fa2008-08-11 22:52:59160 unlink(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28161#endif
162}
initial.commitd7cae122008-07-26 21:49:38163
164// Called by logging functions to ensure that debug_file is initialized
165// and can be used for writing. Returns false if the file could not be
166// initialized. debug_file will be NULL in this case.
167bool InitializeLogFileHandle() {
168 if (log_file)
169 return true;
170
[email protected]614e9fa2008-08-11 22:52:59171 if (!log_file_name) {
172 // Nobody has called InitLogging to specify a debug log file, so here we
173 // initialize the log file name to a default.
[email protected]f6abeba2008-08-08 13:27:28174#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:59175 // On Windows we use the same path as the exe.
176 wchar_t module_name[MAX_PATH];
177 GetModuleFileName(NULL, module_name, MAX_PATH);
178 log_file_name = new std::wstring(module_name);
179 std::wstring::size_type last_backslash =
180 log_file_name->rfind('\\', log_file_name->size());
181 if (last_backslash != std::wstring::npos)
182 log_file_name->erase(last_backslash + 1);
183 *log_file_name += L"debug.log";
184#elif defined(OS_POSIX)
185 // On other platforms we just use the current directory.
186 log_file_name = new std::string("debug.log");
187#endif
initial.commitd7cae122008-07-26 21:49:38188 }
189
[email protected]1d8c2702008-08-19 23:39:32190 if (logging_destination == LOG_ONLY_TO_FILE ||
191 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
[email protected]614e9fa2008-08-11 22:52:59192#if defined(OS_WIN)
[email protected]1d8c2702008-08-19 23:39:32193 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
initial.commitd7cae122008-07-26 21:49:38194 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
195 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
196 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
[email protected]1d8c2702008-08-19 23:39:32197 // try the current directory
198 log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
199 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
200 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
201 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
202 log_file = NULL;
203 return false;
204 }
initial.commitd7cae122008-07-26 21:49:38205 }
[email protected]1d8c2702008-08-19 23:39:32206 SetFilePointer(log_file, 0, 0, FILE_END);
[email protected]f6abeba2008-08-08 13:27:28207#elif defined(OS_POSIX)
[email protected]1d8c2702008-08-19 23:39:32208 log_file = fopen(log_file_name->c_str(), "a");
209 if (log_file == NULL)
210 return false;
[email protected]f6abeba2008-08-08 13:27:28211#endif
[email protected]1d8c2702008-08-19 23:39:32212 }
213
initial.commitd7cae122008-07-26 21:49:38214 return true;
215}
216
217void InitLogMutex() {
[email protected]f6abeba2008-08-08 13:27:28218#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38219 if (!log_mutex) {
220 // \ is not a legal character in mutex names so we replace \ with /
[email protected]614e9fa2008-08-11 22:52:59221 std::wstring safe_name(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38222 std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
223 std::wstring t(L"Global\\");
224 t.append(safe_name);
225 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
226 }
[email protected]f6abeba2008-08-08 13:27:28227#elif defined(OS_POSIX)
228 // statically initialized
229#endif
initial.commitd7cae122008-07-26 21:49:38230}
231
[email protected]f6abeba2008-08-08 13:27:28232void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
initial.commitd7cae122008-07-26 21:49:38233 LogLockingState lock_log, OldFileDeletionState delete_old) {
[email protected]bb975362009-01-21 01:00:22234 g_enable_dcheck =
235 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
initial.commitd7cae122008-07-26 21:49:38236
237 if (log_file) {
238 // calling InitLogging twice or after some log call has already opened the
239 // default log file will re-initialize to the new options
[email protected]f6abeba2008-08-08 13:27:28240 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38241 log_file = NULL;
242 }
243
244 lock_log_file = lock_log;
245 logging_destination = logging_dest;
246
247 // ignore file options if logging is disabled or only to system
248 if (logging_destination == LOG_NONE ||
249 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
250 return;
251
[email protected]614e9fa2008-08-11 22:52:59252 if (!log_file_name)
253 log_file_name = new PathString();
254 *log_file_name = new_log_file;
initial.commitd7cae122008-07-26 21:49:38255 if (delete_old == DELETE_OLD_LOG_FILE)
[email protected]614e9fa2008-08-11 22:52:59256 DeleteFilePath(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38257
258 if (lock_log_file == LOCK_LOG_FILE) {
259 InitLogMutex();
260 } else if (!log_lock) {
261 log_lock = new LockImpl();
262 }
263
264 InitializeLogFileHandle();
265}
266
267void SetMinLogLevel(int level) {
268 min_log_level = level;
269}
270
271int GetMinLogLevel() {
272 return min_log_level;
273}
274
275void SetLogFilterPrefix(const char* filter) {
276 if (log_filter_prefix) {
[email protected]614e9fa2008-08-11 22:52:59277 delete log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:38278 log_filter_prefix = NULL;
279 }
280
[email protected]614e9fa2008-08-11 22:52:59281 if (filter)
282 log_filter_prefix = new std::string(filter);
initial.commitd7cae122008-07-26 21:49:38283}
284
285void SetLogItems(bool enable_process_id, bool enable_thread_id,
286 bool enable_timestamp, bool enable_tickcount) {
287 log_process_id = enable_process_id;
288 log_thread_id = enable_thread_id;
289 log_timestamp = enable_timestamp;
290 log_tickcount = enable_tickcount;
291}
292
293void SetLogAssertHandler(LogAssertHandlerFunction handler) {
294 log_assert_handler = handler;
295}
296
[email protected]fb62a532009-02-12 01:19:05297void SetLogReportHandler(LogReportHandlerFunction handler) {
298 log_report_handler = handler;
299}
300
initial.commitd7cae122008-07-26 21:49:38301// Displays a message box to the user with the error message in it. For
302// Windows programs, it's possible that the message loop is messed up on
303// a fatal error, and creating a MessageBox will cause that message loop
304// to be run. Instead, we try to spawn another process that displays its
305// command line. We look for "Debug Message.exe" in the same directory as
306// the application. If it exists, we use it, otherwise, we use a regular
307// message box.
308void DisplayDebugMessage(const std::string& str) {
309 if (str.empty())
310 return;
311
[email protected]f6abeba2008-08-08 13:27:28312#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38313 // look for the debug dialog program next to our application
314 wchar_t prog_name[MAX_PATH];
315 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
316 wchar_t* backslash = wcsrchr(prog_name, '\\');
317 if (backslash)
318 backslash[1] = 0;
319 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
320
[email protected]3ca4214c12009-03-25 22:12:02321 std::wstring cmdline = base::SysUTF8ToWide(str);
322 if (cmdline.empty())
323 return;
initial.commitd7cae122008-07-26 21:49:38324
325 STARTUPINFO startup_info;
326 memset(&startup_info, 0, sizeof(startup_info));
327 startup_info.cb = sizeof(startup_info);
328
329 PROCESS_INFORMATION process_info;
[email protected]3ca4214c12009-03-25 22:12:02330 if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
initial.commitd7cae122008-07-26 21:49:38331 NULL, &startup_info, &process_info)) {
332 WaitForSingleObject(process_info.hProcess, INFINITE);
333 CloseHandle(process_info.hThread);
334 CloseHandle(process_info.hProcess);
335 } else {
336 // debug process broken, let's just do a message box
[email protected]3ca4214c12009-03-25 22:12:02337 MessageBoxW(NULL, &cmdline[0], L"Fatal error",
initial.commitd7cae122008-07-26 21:49:38338 MB_OK | MB_ICONHAND | MB_TOPMOST);
339 }
[email protected]f6abeba2008-08-08 13:27:28340#else
341 fprintf(stderr, "%s\n", str.c_str());
342#endif
initial.commitd7cae122008-07-26 21:49:38343}
344
[email protected]3f85caa2009-04-14 16:52:11345#if defined(OS_WIN)
346LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
347}
348
349LogMessage::SaveLastError::~SaveLastError() {
350 ::SetLastError(last_error_);
351}
352#endif // defined(OS_WIN)
353
initial.commitd7cae122008-07-26 21:49:38354LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
355 int ctr)
356 : severity_(severity) {
357 Init(file, line);
358}
359
360LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
361 : severity_(LOG_FATAL) {
362 Init(file, line);
363 stream_ << "Check failed: " << (*result.str_);
364}
365
[email protected]fb62a532009-02-12 01:19:05366LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
367 const CheckOpString& result)
368 : severity_(severity) {
369 Init(file, line);
370 stream_ << "Check failed: " << (*result.str_);
371}
372
initial.commitd7cae122008-07-26 21:49:38373LogMessage::LogMessage(const char* file, int line)
374 : severity_(LOG_INFO) {
375 Init(file, line);
376}
377
378LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
379 : severity_(severity) {
380 Init(file, line);
381}
382
383// writes the common header info to the stream
384void LogMessage::Init(const char* file, int line) {
385 // log only the filename
386 const char* last_slash = strrchr(file, '\\');
387 if (last_slash)
388 file = last_slash + 1;
389
390 // TODO(darin): It might be nice if the columns were fixed width.
391
392 stream_ << '[';
393 if (log_process_id)
[email protected]f8588472008-11-05 23:17:24394 stream_ << CurrentProcessId() << ':';
initial.commitd7cae122008-07-26 21:49:38395 if (log_thread_id)
[email protected]f8588472008-11-05 23:17:24396 stream_ << CurrentThreadId() << ':';
initial.commitd7cae122008-07-26 21:49:38397 if (log_timestamp) {
[email protected]defcd8f32009-05-13 00:03:43398 time_t t = time(NULL);
initial.commitd7cae122008-07-26 21:49:38399 struct tm local_time = {0};
[email protected]defcd8f32009-05-13 00:03:43400#if _MSC_VER >= 1400
initial.commitd7cae122008-07-26 21:49:38401 localtime_s(&local_time, &t);
initial.commitd7cae122008-07-26 21:49:38402#else
[email protected]defcd8f32009-05-13 00:03:43403 localtime_r(&t, &local_time);
initial.commitd7cae122008-07-26 21:49:38404#endif
[email protected]defcd8f32009-05-13 00:03:43405 struct tm* tm_time = &local_time;
initial.commitd7cae122008-07-26 21:49:38406 stream_ << std::setfill('0')
407 << std::setw(2) << 1 + tm_time->tm_mon
408 << std::setw(2) << tm_time->tm_mday
409 << '/'
410 << std::setw(2) << tm_time->tm_hour
411 << std::setw(2) << tm_time->tm_min
412 << std::setw(2) << tm_time->tm_sec
413 << ':';
414 }
415 if (log_tickcount)
[email protected]f8588472008-11-05 23:17:24416 stream_ << TickCount() << ':';
[email protected]52a261f2009-03-03 15:01:12417 stream_ << log_severity_names[severity_] << ":" << file <<
418 "(" << line << ")] ";
initial.commitd7cae122008-07-26 21:49:38419
420 message_start_ = stream_.tellp();
421}
422
423LogMessage::~LogMessage() {
424 // TODO(brettw) modify the macros so that nothing is executed when the log
425 // level is too high.
426 if (severity_ < min_log_level)
427 return;
428
429 std::string str_newline(stream_.str());
[email protected]1d8c2702008-08-19 23:39:32430#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38431 str_newline.append("\r\n");
[email protected]1d8c2702008-08-19 23:39:32432#else
433 str_newline.append("\n");
434#endif
initial.commitd7cae122008-07-26 21:49:38435
436 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
[email protected]614e9fa2008-08-11 22:52:59437 str_newline.compare(message_start_, log_filter_prefix->size(),
438 log_filter_prefix->data()) != 0) {
initial.commitd7cae122008-07-26 21:49:38439 return;
440 }
441
442 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
[email protected]f6abeba2008-08-08 13:27:28443 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
444#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38445 OutputDebugStringA(str_newline.c_str());
[email protected]107bc0f12008-08-26 17:48:18446 if (severity_ >= kAlwaysPrintErrorLevel)
447#endif
[email protected]31ae0352008-08-25 23:28:37448 // TODO(erikkay): this interferes with the layout tests since it grabs
449 // stderr and stdout and diffs them against known data. Our info and warn
450 // logs add noise to that. Ideally, the layout tests would set the log
451 // level to ignore anything below error. When that happens, we should
452 // take this fprintf out of the #else so that Windows users can benefit
453 // from the output when running tests from the command-line. In the
454 // meantime, we leave this in for Mac and Linux, but until this is fixed
455 // they won't be able to pass any layout tests that have info or warn logs.
456 // See http://b/1343647
[email protected]a33c9892008-08-25 20:10:31457 fprintf(stderr, "%s", str_newline.c_str());
458 } else if (severity_ >= kAlwaysPrintErrorLevel) {
459 // When we're only outputting to a log file, above a certain log level, we
460 // should still output to stderr so that we can better detect and diagnose
461 // problems with unit tests, especially on the buildbots.
462 fprintf(stderr, "%s", str_newline.c_str());
[email protected]f6abeba2008-08-08 13:27:28463 }
[email protected]52a261f2009-03-03 15:01:12464
initial.commitd7cae122008-07-26 21:49:38465 // write to log file
466 if (logging_destination != LOG_NONE &&
467 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
468 InitializeLogFileHandle()) {
[email protected]52a261f2009-03-03 15:01:12469 // We can have multiple threads and/or processes, so try to prevent them
470 // from clobbering each other's writes.
initial.commitd7cae122008-07-26 21:49:38471 if (lock_log_file == LOCK_LOG_FILE) {
472 // Ensure that the mutex is initialized in case the client app did not
[email protected]52a261f2009-03-03 15:01:12473 // call InitLogging. This is not thread safe. See below.
initial.commitd7cae122008-07-26 21:49:38474 InitLogMutex();
475
[email protected]f6abeba2008-08-08 13:27:28476#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38477 DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
478 DCHECK(r != WAIT_ABANDONED);
[email protected]f6abeba2008-08-08 13:27:28479#elif defined(OS_POSIX)
480 pthread_mutex_lock(&log_mutex);
481#endif
initial.commitd7cae122008-07-26 21:49:38482 } else {
483 // use the lock
484 if (!log_lock) {
485 // The client app did not call InitLogging, and so the lock has not
486 // been created. We do this on demand, but if two threads try to do
487 // this at the same time, there will be a race condition to create
488 // the lock. This is why InitLogging should be called from the main
489 // thread at the beginning of execution.
490 log_lock = new LockImpl();
491 }
492 log_lock->Lock();
493 }
494
[email protected]f6abeba2008-08-08 13:27:28495#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38496 SetFilePointer(log_file, 0, 0, SEEK_END);
497 DWORD num_written;
[email protected]52a261f2009-03-03 15:01:12498 WriteFile(log_file,
[email protected]5982f1f32009-03-03 15:10:58499 static_cast<const void*>(str_newline.c_str()),
[email protected]52a261f2009-03-03 15:01:12500 static_cast<DWORD>(str_newline.length()),
501 &num_written,
502 NULL);
[email protected]f6abeba2008-08-08 13:27:28503#else
504 fprintf(log_file, "%s", str_newline.c_str());
505#endif
initial.commitd7cae122008-07-26 21:49:38506
507 if (lock_log_file == LOCK_LOG_FILE) {
[email protected]f6abeba2008-08-08 13:27:28508#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38509 ReleaseMutex(log_mutex);
[email protected]f6abeba2008-08-08 13:27:28510#elif defined(OS_POSIX)
511 pthread_mutex_unlock(&log_mutex);
512#endif
initial.commitd7cae122008-07-26 21:49:38513 } else {
514 log_lock->Unlock();
515 }
516 }
517
518 if (severity_ == LOG_FATAL) {
519 // display a message or break into the debugger on a fatal error
[email protected]1ffe08c12008-08-13 11:15:11520 if (DebugUtil::BeingDebugged()) {
521 DebugUtil::BreakDebugger();
522 } else {
[email protected]96fd0032009-04-24 00:13:08523#ifndef NDEBUG
524 // Dump a stack trace on a fatal.
525 StackTrace trace;
526 stream_ << "\n"; // Newline to separate from log message.
527 trace.OutputToStream(&stream_);
528#endif
529
initial.commitd7cae122008-07-26 21:49:38530 if (log_assert_handler) {
531 // make a copy of the string for the handler out of paranoia
532 log_assert_handler(std::string(stream_.str()));
533 } else {
[email protected]4d5901272008-11-06 00:33:50534 // Don't use the string with the newline, get a fresh version to send to
535 // the debug message process. We also don't display assertions to the
536 // user in release mode. The enduser can't do anything with this
537 // information, and displaying message boxes when the application is
538 // hosed can cause additional problems.
539#ifndef NDEBUG
initial.commitd7cae122008-07-26 21:49:38540 DisplayDebugMessage(stream_.str());
[email protected]4d5901272008-11-06 00:33:50541#endif
initial.commitd7cae122008-07-26 21:49:38542 // Crash the process to generate a dump.
[email protected]1ffe08c12008-08-13 11:15:11543 DebugUtil::BreakDebugger();
initial.commitd7cae122008-07-26 21:49:38544 }
545 }
[email protected]fb62a532009-02-12 01:19:05546 } else if (severity_ == LOG_ERROR_REPORT) {
547 // We are here only if the user runs with --enable-dcheck in release mode.
548 if (log_report_handler) {
549 log_report_handler(std::string(stream_.str()));
550 } else {
551 DisplayDebugMessage(stream_.str());
552 }
initial.commitd7cae122008-07-26 21:49:38553 }
554}
555
556void CloseLogFile() {
557 if (!log_file)
558 return;
559
[email protected]f6abeba2008-08-08 13:27:28560 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38561 log_file = NULL;
562}
563
[email protected]96fd0032009-04-24 00:13:08564} // namespace logging
initial.commitd7cae122008-07-26 21:49:38565
566std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
[email protected]15af80e2008-08-07 03:11:42567 return out << base::SysWideToUTF8(std::wstring(wstr));
initial.commitd7cae122008-07-26 21:49:38568}