blob: a1e7cb2faaf51120da385caed02ef0ffc99b230b [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
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]15af80e2008-08-07 03:11:42321 // Stupid CreateProcess requires a non-const command line and may modify it.
322 // We also want to use the wide string.
323 std::wstring cmdline_string = base::SysUTF8ToWide(str);
324 wchar_t* cmdline = const_cast<wchar_t*>(cmdline_string.c_str());
initial.commitd7cae122008-07-26 21:49:38325
326 STARTUPINFO startup_info;
327 memset(&startup_info, 0, sizeof(startup_info));
328 startup_info.cb = sizeof(startup_info);
329
330 PROCESS_INFORMATION process_info;
[email protected]15af80e2008-08-07 03:11:42331 if (CreateProcessW(prog_name, cmdline, NULL, NULL, false, 0, NULL,
initial.commitd7cae122008-07-26 21:49:38332 NULL, &startup_info, &process_info)) {
333 WaitForSingleObject(process_info.hProcess, INFINITE);
334 CloseHandle(process_info.hThread);
335 CloseHandle(process_info.hProcess);
336 } else {
337 // debug process broken, let's just do a message box
[email protected]15af80e2008-08-07 03:11:42338 MessageBoxW(NULL, cmdline, L"Fatal error",
initial.commitd7cae122008-07-26 21:49:38339 MB_OK | MB_ICONHAND | MB_TOPMOST);
340 }
[email protected]f6abeba2008-08-08 13:27:28341#else
342 fprintf(stderr, "%s\n", str.c_str());
343#endif
initial.commitd7cae122008-07-26 21:49:38344}
345
346LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
347 int ctr)
348 : severity_(severity) {
349 Init(file, line);
350}
351
352LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
353 : severity_(LOG_FATAL) {
354 Init(file, line);
355 stream_ << "Check failed: " << (*result.str_);
356}
357
[email protected]fb62a532009-02-12 01:19:05358LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
359 const CheckOpString& result)
360 : severity_(severity) {
361 Init(file, line);
362 stream_ << "Check failed: " << (*result.str_);
363}
364
initial.commitd7cae122008-07-26 21:49:38365LogMessage::LogMessage(const char* file, int line)
366 : severity_(LOG_INFO) {
367 Init(file, line);
368}
369
370LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
371 : severity_(severity) {
372 Init(file, line);
373}
374
375// writes the common header info to the stream
376void LogMessage::Init(const char* file, int line) {
377 // log only the filename
378 const char* last_slash = strrchr(file, '\\');
379 if (last_slash)
380 file = last_slash + 1;
381
382 // TODO(darin): It might be nice if the columns were fixed width.
383
384 stream_ << '[';
385 if (log_process_id)
[email protected]f8588472008-11-05 23:17:24386 stream_ << CurrentProcessId() << ':';
initial.commitd7cae122008-07-26 21:49:38387 if (log_thread_id)
[email protected]f8588472008-11-05 23:17:24388 stream_ << CurrentThreadId() << ':';
initial.commitd7cae122008-07-26 21:49:38389 if (log_timestamp) {
390 time_t t = time(NULL);
391#if _MSC_VER >= 1400
392 struct tm local_time = {0};
393 localtime_s(&local_time, &t);
394 struct tm* tm_time = &local_time;
395#else
396 struct tm* tm_time = localtime(&t);
397#endif
398 stream_ << std::setfill('0')
399 << std::setw(2) << 1 + tm_time->tm_mon
400 << std::setw(2) << tm_time->tm_mday
401 << '/'
402 << std::setw(2) << tm_time->tm_hour
403 << std::setw(2) << tm_time->tm_min
404 << std::setw(2) << tm_time->tm_sec
405 << ':';
406 }
407 if (log_tickcount)
[email protected]f8588472008-11-05 23:17:24408 stream_ << TickCount() << ':';
[email protected]52a261f2009-03-03 15:01:12409 stream_ << log_severity_names[severity_] << ":" << file <<
410 "(" << line << ")] ";
initial.commitd7cae122008-07-26 21:49:38411
412 message_start_ = stream_.tellp();
413}
414
415LogMessage::~LogMessage() {
416 // TODO(brettw) modify the macros so that nothing is executed when the log
417 // level is too high.
418 if (severity_ < min_log_level)
419 return;
420
421 std::string str_newline(stream_.str());
[email protected]1d8c2702008-08-19 23:39:32422#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38423 str_newline.append("\r\n");
[email protected]1d8c2702008-08-19 23:39:32424#else
425 str_newline.append("\n");
426#endif
initial.commitd7cae122008-07-26 21:49:38427
428 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
[email protected]614e9fa2008-08-11 22:52:59429 str_newline.compare(message_start_, log_filter_prefix->size(),
430 log_filter_prefix->data()) != 0) {
initial.commitd7cae122008-07-26 21:49:38431 return;
432 }
433
434 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
[email protected]f6abeba2008-08-08 13:27:28435 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
436#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38437 OutputDebugStringA(str_newline.c_str());
[email protected]107bc0f12008-08-26 17:48:18438 if (severity_ >= kAlwaysPrintErrorLevel)
439#endif
[email protected]31ae0352008-08-25 23:28:37440 // TODO(erikkay): this interferes with the layout tests since it grabs
441 // stderr and stdout and diffs them against known data. Our info and warn
442 // logs add noise to that. Ideally, the layout tests would set the log
443 // level to ignore anything below error. When that happens, we should
444 // take this fprintf out of the #else so that Windows users can benefit
445 // from the output when running tests from the command-line. In the
446 // meantime, we leave this in for Mac and Linux, but until this is fixed
447 // they won't be able to pass any layout tests that have info or warn logs.
448 // See http://b/1343647
[email protected]a33c9892008-08-25 20:10:31449 fprintf(stderr, "%s", str_newline.c_str());
450 } else if (severity_ >= kAlwaysPrintErrorLevel) {
451 // When we're only outputting to a log file, above a certain log level, we
452 // should still output to stderr so that we can better detect and diagnose
453 // problems with unit tests, especially on the buildbots.
454 fprintf(stderr, "%s", str_newline.c_str());
[email protected]f6abeba2008-08-08 13:27:28455 }
[email protected]52a261f2009-03-03 15:01:12456
initial.commitd7cae122008-07-26 21:49:38457 // write to log file
458 if (logging_destination != LOG_NONE &&
459 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
460 InitializeLogFileHandle()) {
[email protected]52a261f2009-03-03 15:01:12461 // We can have multiple threads and/or processes, so try to prevent them
462 // from clobbering each other's writes.
initial.commitd7cae122008-07-26 21:49:38463 if (lock_log_file == LOCK_LOG_FILE) {
464 // Ensure that the mutex is initialized in case the client app did not
[email protected]52a261f2009-03-03 15:01:12465 // call InitLogging. This is not thread safe. See below.
initial.commitd7cae122008-07-26 21:49:38466 InitLogMutex();
467
[email protected]f6abeba2008-08-08 13:27:28468#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38469 DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
470 DCHECK(r != WAIT_ABANDONED);
[email protected]f6abeba2008-08-08 13:27:28471#elif defined(OS_POSIX)
472 pthread_mutex_lock(&log_mutex);
473#endif
initial.commitd7cae122008-07-26 21:49:38474 } else {
475 // use the lock
476 if (!log_lock) {
477 // The client app did not call InitLogging, and so the lock has not
478 // been created. We do this on demand, but if two threads try to do
479 // this at the same time, there will be a race condition to create
480 // the lock. This is why InitLogging should be called from the main
481 // thread at the beginning of execution.
482 log_lock = new LockImpl();
483 }
484 log_lock->Lock();
485 }
486
[email protected]f6abeba2008-08-08 13:27:28487#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38488 SetFilePointer(log_file, 0, 0, SEEK_END);
489 DWORD num_written;
[email protected]52a261f2009-03-03 15:01:12490 WriteFile(log_file,
491 static_cast<void*>(str_newline.c_str()),
492 static_cast<DWORD>(str_newline.length()),
493 &num_written,
494 NULL);
[email protected]f6abeba2008-08-08 13:27:28495#else
496 fprintf(log_file, "%s", str_newline.c_str());
497#endif
initial.commitd7cae122008-07-26 21:49:38498
499 if (lock_log_file == LOCK_LOG_FILE) {
[email protected]f6abeba2008-08-08 13:27:28500#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38501 ReleaseMutex(log_mutex);
[email protected]f6abeba2008-08-08 13:27:28502#elif defined(OS_POSIX)
503 pthread_mutex_unlock(&log_mutex);
504#endif
initial.commitd7cae122008-07-26 21:49:38505 } else {
506 log_lock->Unlock();
507 }
508 }
509
510 if (severity_ == LOG_FATAL) {
511 // display a message or break into the debugger on a fatal error
[email protected]1ffe08c12008-08-13 11:15:11512 if (DebugUtil::BeingDebugged()) {
513 DebugUtil::BreakDebugger();
514 } else {
initial.commitd7cae122008-07-26 21:49:38515 if (log_assert_handler) {
516 // make a copy of the string for the handler out of paranoia
517 log_assert_handler(std::string(stream_.str()));
518 } else {
[email protected]4d5901272008-11-06 00:33:50519 // Don't use the string with the newline, get a fresh version to send to
520 // the debug message process. We also don't display assertions to the
521 // user in release mode. The enduser can't do anything with this
522 // information, and displaying message boxes when the application is
523 // hosed can cause additional problems.
524#ifndef NDEBUG
initial.commitd7cae122008-07-26 21:49:38525 DisplayDebugMessage(stream_.str());
[email protected]4d5901272008-11-06 00:33:50526#endif
initial.commitd7cae122008-07-26 21:49:38527 // Crash the process to generate a dump.
[email protected]1ffe08c12008-08-13 11:15:11528 DebugUtil::BreakDebugger();
529 // TODO(mmentovai): when we have breakpad support, generate a breakpad
530 // dump, but until then, do not invoke the Apple crash reporter.
initial.commitd7cae122008-07-26 21:49:38531 }
532 }
[email protected]fb62a532009-02-12 01:19:05533 } else if (severity_ == LOG_ERROR_REPORT) {
534 // We are here only if the user runs with --enable-dcheck in release mode.
535 if (log_report_handler) {
536 log_report_handler(std::string(stream_.str()));
537 } else {
538 DisplayDebugMessage(stream_.str());
539 }
initial.commitd7cae122008-07-26 21:49:38540 }
541}
542
543void CloseLogFile() {
544 if (!log_file)
545 return;
546
[email protected]f6abeba2008-08-08 13:27:28547 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38548 log_file = NULL;
549}
550
551} // namespace logging
552
553std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
[email protected]15af80e2008-08-07 03:11:42554 return out << base::SysWideToUTF8(std::wstring(wstr));
initial.commitd7cae122008-07-26 21:49:38555}