blob: 227085fa912db84bfd1b88852f82e8d9047b9d3d [file] [log] [blame]
initial.commit3f4a7322008-07-27 06:49:38 +09001// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
darin@google.com12d40bb2008-08-20 03:36:23 +090030#include "base/logging.h"
pinkerton@google.com56053fe2008-08-08 22:27:28 +090031
darin@google.com12d40bb2008-08-20 03:36:23 +090032#if defined(OS_WIN)
pinkerton@google.com56053fe2008-08-08 22:27:28 +090033#include <windows.h>
34typedef HANDLE FileHandle;
35typedef HANDLE MutexHandle;
36#endif
37
38#if defined(OS_MACOSX)
39#include <CoreFoundation/CoreFoundation.h>
40#include <mach/mach.h>
41#include <mach/mach_time.h>
42#include <mach-o/dyld.h>
evanm@google.com4487dd72008-08-12 07:52:59 +090043#endif
44
45#if defined(OS_POSIX)
pinkerton@google.com56053fe2008-08-08 22:27:28 +090046#include <stdlib.h>
47#include <stdio.h>
48#include <string.h>
49#include <unistd.h>
50#define MAX_PATH PATH_MAX
51typedef FILE* FileHandle;
52typedef pthread_mutex_t* MutexHandle;
53#endif
54
initial.commit3f4a7322008-07-27 06:49:38 +090055#include <ctime>
56#include <iomanip>
57#include <cstring>
initial.commit3f4a7322008-07-27 06:49:38 +090058#include <algorithm>
darin@google.com12d40bb2008-08-20 03:36:23 +090059
initial.commit3f4a7322008-07-27 06:49:38 +090060#include "base/base_switches.h"
61#include "base/command_line.h"
deanm@google.comc2b652a2008-08-13 20:15:11 +090062#include "base/debug_util.h"
initial.commit3f4a7322008-07-27 06:49:38 +090063#include "base/lock_impl.h"
darin@google.com12d40bb2008-08-20 03:36:23 +090064#include "base/notimplemented.h"
deanm@google.coma65ec9f2008-08-19 22:19:24 +090065#include "base/string_piece.h"
pinkerton@google.com56053fe2008-08-08 22:27:28 +090066#include "base/string_util.h"
brettw@google.com7bea9d12008-08-07 12:11:42 +090067#include "base/sys_string_conversions.h"
pinkerton@google.com56053fe2008-08-08 22:27:28 +090068
initial.commit3f4a7322008-07-27 06:49:38 +090069namespace logging {
70
71bool g_enable_dcheck = false;
72
73const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
74 "INFO", "WARNING", "ERROR", "FATAL" };
75
76int min_log_level = 0;
77LogLockingState lock_log_file = LOCK_LOG_FILE;
mmentovai@google.comf0944f32008-08-20 08:39:32 +090078
79// The default set here for logging_destination will only be used if
80// InitLogging is not called. On Windows, use a file next to the exe;
81// on POSIX platforms, where it may not even be possible to locate the
82// executable on disk, use stderr.
evanm@google.come41d3b32008-08-15 10:04:11 +090083#if defined(OS_WIN)
mmentovai@google.com0f8dd7e2008-08-23 02:09:34 +090084LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
evanm@google.come41d3b32008-08-15 10:04:11 +090085#elif defined(OS_POSIX)
mmentovai@google.comf0944f32008-08-20 08:39:32 +090086LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
evanm@google.come41d3b32008-08-15 10:04:11 +090087#endif
initial.commit3f4a7322008-07-27 06:49:38 +090088
89const int kMaxFilteredLogLevel = LOG_WARNING;
evanm@google.com4487dd72008-08-12 07:52:59 +090090std::string* log_filter_prefix;
initial.commit3f4a7322008-07-27 06:49:38 +090091
evanm@google.com4487dd72008-08-12 07:52:59 +090092// Which log file to use? This is initialized by InitLogging or
initial.commit3f4a7322008-07-27 06:49:38 +090093// will be lazily initialized to the default value when it is
94// first needed.
pinkerton@google.com56053fe2008-08-08 22:27:28 +090095#if defined(OS_WIN)
96typedef wchar_t PathChar;
evanm@google.com4487dd72008-08-12 07:52:59 +090097typedef std::wstring PathString;
pinkerton@google.com56053fe2008-08-08 22:27:28 +090098#else
99typedef char PathChar;
evanm@google.com4487dd72008-08-12 07:52:59 +0900100typedef std::string PathString;
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900101#endif
evanm@google.com4487dd72008-08-12 07:52:59 +0900102PathString* log_file_name = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +0900103
104// this file is lazily opened and the handle may be NULL
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900105FileHandle log_file = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +0900106
107// what should be prepended to each message?
108bool log_process_id = false;
109bool log_thread_id = false;
110bool log_timestamp = true;
111bool log_tickcount = false;
112
113// An assert handler override specified by the client to be called instead of
114// the debug message dialog.
115LogAssertHandlerFunction log_assert_handler = NULL;
116
117// The lock is used if log file locking is false. It helps us avoid problems
118// with multiple threads writing to the log file at the same time. Use
119// LockImpl directly instead of using Lock, because Lock makes logging calls.
120static LockImpl* log_lock = NULL;
121
122// When we don't use a lock, we are using a global mutex. We need to do this
123// because LockFileEx is not thread safe.
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900124#if defined(OS_WIN)
125MutexHandle log_mutex = NULL;
126#elif defined(OS_POSIX)
127pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
128#endif
129
130// Helper functions to wrap platform differences.
131
132int32 CurrentProcessId() {
133#if defined(OS_WIN)
134 return GetCurrentProcessId();
135#elif defined(OS_POSIX)
136 return getpid();
137#endif
138}
139
140int32 CurrentThreadId() {
141#if defined(OS_WIN)
142 return GetCurrentThreadId();
143#elif defined(OS_MACOSX)
144 return mach_thread_self();
145#else
ericroman@google.com1af64932008-08-12 03:08:22 +0900146 NOTIMPLEMENTED();
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900147 return 0;
148#endif
149}
150
151uint64 TickCount() {
152#if defined(OS_WIN)
153 return GetTickCount();
154#elif defined(OS_MACOSX)
155 return mach_absolute_time();
156#else
ericroman@google.com1af64932008-08-12 03:08:22 +0900157 NOTIMPLEMENTED();
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900158 return 0;
159#endif
160}
161
162void CloseFile(FileHandle log) {
163#if defined(OS_WIN)
164 CloseHandle(log);
165#else
166 fclose(log);
167#endif
168}
169
evanm@google.com4487dd72008-08-12 07:52:59 +0900170void DeleteFilePath(const PathString& log_name) {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900171#if defined(OS_WIN)
evanm@google.com4487dd72008-08-12 07:52:59 +0900172 DeleteFile(log_name.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900173#else
evanm@google.com4487dd72008-08-12 07:52:59 +0900174 unlink(log_name.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900175#endif
176}
initial.commit3f4a7322008-07-27 06:49:38 +0900177
178// Called by logging functions to ensure that debug_file is initialized
179// and can be used for writing. Returns false if the file could not be
180// initialized. debug_file will be NULL in this case.
181bool InitializeLogFileHandle() {
182 if (log_file)
183 return true;
184
evanm@google.com4487dd72008-08-12 07:52:59 +0900185 if (!log_file_name) {
186 // Nobody has called InitLogging to specify a debug log file, so here we
187 // initialize the log file name to a default.
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900188#if defined(OS_WIN)
evanm@google.com4487dd72008-08-12 07:52:59 +0900189 // On Windows we use the same path as the exe.
190 wchar_t module_name[MAX_PATH];
191 GetModuleFileName(NULL, module_name, MAX_PATH);
192 log_file_name = new std::wstring(module_name);
193 std::wstring::size_type last_backslash =
194 log_file_name->rfind('\\', log_file_name->size());
195 if (last_backslash != std::wstring::npos)
196 log_file_name->erase(last_backslash + 1);
197 *log_file_name += L"debug.log";
198#elif defined(OS_POSIX)
199 // On other platforms we just use the current directory.
200 log_file_name = new std::string("debug.log");
201#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900202 }
203
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900204 if (logging_destination == LOG_ONLY_TO_FILE ||
205 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
evanm@google.com4487dd72008-08-12 07:52:59 +0900206#if defined(OS_WIN)
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900207 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
initial.commit3f4a7322008-07-27 06:49:38 +0900208 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
209 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
210 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900211 // try the current directory
212 log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
213 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
214 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
215 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
216 log_file = NULL;
217 return false;
218 }
initial.commit3f4a7322008-07-27 06:49:38 +0900219 }
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900220 SetFilePointer(log_file, 0, 0, FILE_END);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900221#elif defined(OS_POSIX)
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900222 log_file = fopen(log_file_name->c_str(), "a");
223 if (log_file == NULL)
224 return false;
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900225#endif
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900226 }
227
initial.commit3f4a7322008-07-27 06:49:38 +0900228 return true;
229}
230
231void InitLogMutex() {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900232#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900233 if (!log_mutex) {
234 // \ is not a legal character in mutex names so we replace \ with /
evanm@google.com4487dd72008-08-12 07:52:59 +0900235 std::wstring safe_name(*log_file_name);
initial.commit3f4a7322008-07-27 06:49:38 +0900236 std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
237 std::wstring t(L"Global\\");
238 t.append(safe_name);
239 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
240 }
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900241#elif defined(OS_POSIX)
242 // statically initialized
243#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900244}
245
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900246void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
initial.commit3f4a7322008-07-27 06:49:38 +0900247 LogLockingState lock_log, OldFileDeletionState delete_old) {
248 g_enable_dcheck = CommandLine().HasSwitch(switches::kEnableDCHECK);
249
250 if (log_file) {
251 // calling InitLogging twice or after some log call has already opened the
252 // default log file will re-initialize to the new options
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900253 CloseFile(log_file);
initial.commit3f4a7322008-07-27 06:49:38 +0900254 log_file = NULL;
255 }
256
257 lock_log_file = lock_log;
258 logging_destination = logging_dest;
259
260 // ignore file options if logging is disabled or only to system
261 if (logging_destination == LOG_NONE ||
262 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
263 return;
264
evanm@google.com4487dd72008-08-12 07:52:59 +0900265 if (!log_file_name)
266 log_file_name = new PathString();
267 *log_file_name = new_log_file;
initial.commit3f4a7322008-07-27 06:49:38 +0900268 if (delete_old == DELETE_OLD_LOG_FILE)
evanm@google.com4487dd72008-08-12 07:52:59 +0900269 DeleteFilePath(*log_file_name);
initial.commit3f4a7322008-07-27 06:49:38 +0900270
271 if (lock_log_file == LOCK_LOG_FILE) {
272 InitLogMutex();
273 } else if (!log_lock) {
274 log_lock = new LockImpl();
275 }
276
277 InitializeLogFileHandle();
278}
279
280void SetMinLogLevel(int level) {
281 min_log_level = level;
282}
283
284int GetMinLogLevel() {
285 return min_log_level;
286}
287
288void SetLogFilterPrefix(const char* filter) {
289 if (log_filter_prefix) {
evanm@google.com4487dd72008-08-12 07:52:59 +0900290 delete log_filter_prefix;
initial.commit3f4a7322008-07-27 06:49:38 +0900291 log_filter_prefix = NULL;
292 }
293
evanm@google.com4487dd72008-08-12 07:52:59 +0900294 if (filter)
295 log_filter_prefix = new std::string(filter);
initial.commit3f4a7322008-07-27 06:49:38 +0900296}
297
298void SetLogItems(bool enable_process_id, bool enable_thread_id,
299 bool enable_timestamp, bool enable_tickcount) {
300 log_process_id = enable_process_id;
301 log_thread_id = enable_thread_id;
302 log_timestamp = enable_timestamp;
303 log_tickcount = enable_tickcount;
304}
305
306void SetLogAssertHandler(LogAssertHandlerFunction handler) {
307 log_assert_handler = handler;
308}
309
310// Displays a message box to the user with the error message in it. For
311// Windows programs, it's possible that the message loop is messed up on
312// a fatal error, and creating a MessageBox will cause that message loop
313// to be run. Instead, we try to spawn another process that displays its
314// command line. We look for "Debug Message.exe" in the same directory as
315// the application. If it exists, we use it, otherwise, we use a regular
316// message box.
317void DisplayDebugMessage(const std::string& str) {
318 if (str.empty())
319 return;
320
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900321#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900322 // look for the debug dialog program next to our application
323 wchar_t prog_name[MAX_PATH];
324 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
325 wchar_t* backslash = wcsrchr(prog_name, '\\');
326 if (backslash)
327 backslash[1] = 0;
328 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
329
brettw@google.com7bea9d12008-08-07 12:11:42 +0900330 // Stupid CreateProcess requires a non-const command line and may modify it.
331 // We also want to use the wide string.
332 std::wstring cmdline_string = base::SysUTF8ToWide(str);
333 wchar_t* cmdline = const_cast<wchar_t*>(cmdline_string.c_str());
initial.commit3f4a7322008-07-27 06:49:38 +0900334
335 STARTUPINFO startup_info;
336 memset(&startup_info, 0, sizeof(startup_info));
337 startup_info.cb = sizeof(startup_info);
338
339 PROCESS_INFORMATION process_info;
brettw@google.com7bea9d12008-08-07 12:11:42 +0900340 if (CreateProcessW(prog_name, cmdline, NULL, NULL, false, 0, NULL,
initial.commit3f4a7322008-07-27 06:49:38 +0900341 NULL, &startup_info, &process_info)) {
342 WaitForSingleObject(process_info.hProcess, INFINITE);
343 CloseHandle(process_info.hThread);
344 CloseHandle(process_info.hProcess);
345 } else {
346 // debug process broken, let's just do a message box
brettw@google.com7bea9d12008-08-07 12:11:42 +0900347 MessageBoxW(NULL, cmdline, L"Fatal error",
initial.commit3f4a7322008-07-27 06:49:38 +0900348 MB_OK | MB_ICONHAND | MB_TOPMOST);
349 }
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900350#else
351 fprintf(stderr, "%s\n", str.c_str());
352#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900353}
354
355LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
356 int ctr)
357 : severity_(severity) {
358 Init(file, line);
359}
360
361LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
362 : severity_(LOG_FATAL) {
363 Init(file, line);
364 stream_ << "Check failed: " << (*result.str_);
365}
366
367LogMessage::LogMessage(const char* file, int line)
368 : severity_(LOG_INFO) {
369 Init(file, line);
370}
371
372LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
373 : severity_(severity) {
374 Init(file, line);
375}
376
377// writes the common header info to the stream
378void LogMessage::Init(const char* file, int line) {
379 // log only the filename
380 const char* last_slash = strrchr(file, '\\');
381 if (last_slash)
382 file = last_slash + 1;
383
384 // TODO(darin): It might be nice if the columns were fixed width.
385
386 stream_ << '[';
387 if (log_process_id)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900388 stream_ << CurrentProcessId() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900389 if (log_thread_id)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900390 stream_ << CurrentThreadId() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900391 if (log_timestamp) {
392 time_t t = time(NULL);
393#if _MSC_VER >= 1400
394 struct tm local_time = {0};
395 localtime_s(&local_time, &t);
396 struct tm* tm_time = &local_time;
397#else
398 struct tm* tm_time = localtime(&t);
399#endif
400 stream_ << std::setfill('0')
401 << std::setw(2) << 1 + tm_time->tm_mon
402 << std::setw(2) << tm_time->tm_mday
403 << '/'
404 << std::setw(2) << tm_time->tm_hour
405 << std::setw(2) << tm_time->tm_min
406 << std::setw(2) << tm_time->tm_sec
407 << ':';
408 }
409 if (log_tickcount)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900410 stream_ << TickCount() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900411 stream_ << log_severity_names[severity_] << ":" << file << "(" << line << ")] ";
412
413 message_start_ = stream_.tellp();
414}
415
416LogMessage::~LogMessage() {
417 // TODO(brettw) modify the macros so that nothing is executed when the log
418 // level is too high.
419 if (severity_ < min_log_level)
420 return;
421
422 std::string str_newline(stream_.str());
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900423#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900424 str_newline.append("\r\n");
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900425#else
426 str_newline.append("\n");
427#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900428
429 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
evanm@google.com4487dd72008-08-12 07:52:59 +0900430 str_newline.compare(message_start_, log_filter_prefix->size(),
431 log_filter_prefix->data()) != 0) {
initial.commit3f4a7322008-07-27 06:49:38 +0900432 return;
433 }
434
435 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900436 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
437#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900438 OutputDebugStringA(str_newline.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900439#else
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900440 fprintf(stderr, "%s", str_newline.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900441#endif
442 }
443
initial.commit3f4a7322008-07-27 06:49:38 +0900444 // write to log file
445 if (logging_destination != LOG_NONE &&
446 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
447 InitializeLogFileHandle()) {
448 // we can have multiple threads and/or processes, so try to prevent them from
449 // clobbering each other's writes
450 if (lock_log_file == LOCK_LOG_FILE) {
451 // Ensure that the mutex is initialized in case the client app did not
452 // call InitLogging. This is not thread safe. See below
453 InitLogMutex();
454
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900455#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900456 DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
457 DCHECK(r != WAIT_ABANDONED);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900458#elif defined(OS_POSIX)
459 pthread_mutex_lock(&log_mutex);
460#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900461 } else {
462 // use the lock
463 if (!log_lock) {
464 // The client app did not call InitLogging, and so the lock has not
465 // been created. We do this on demand, but if two threads try to do
466 // this at the same time, there will be a race condition to create
467 // the lock. This is why InitLogging should be called from the main
468 // thread at the beginning of execution.
469 log_lock = new LockImpl();
470 }
471 log_lock->Lock();
472 }
473
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900474#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900475 SetFilePointer(log_file, 0, 0, SEEK_END);
476 DWORD num_written;
477 WriteFile(log_file, (void*)str_newline.c_str(), (DWORD)str_newline.length(), &num_written, NULL);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900478#else
479 fprintf(log_file, "%s", str_newline.c_str());
480#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900481
482 if (lock_log_file == LOCK_LOG_FILE) {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900483#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900484 ReleaseMutex(log_mutex);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900485#elif defined(OS_POSIX)
486 pthread_mutex_unlock(&log_mutex);
487#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900488 } else {
489 log_lock->Unlock();
490 }
491 }
492
493 if (severity_ == LOG_FATAL) {
494 // display a message or break into the debugger on a fatal error
deanm@google.comc2b652a2008-08-13 20:15:11 +0900495 if (DebugUtil::BeingDebugged()) {
496 DebugUtil::BreakDebugger();
497 } else {
initial.commit3f4a7322008-07-27 06:49:38 +0900498 if (log_assert_handler) {
499 // make a copy of the string for the handler out of paranoia
500 log_assert_handler(std::string(stream_.str()));
501 } else {
502 // don't use the string with the newline, get a fresh version to send to
503 // the debug message process
504 DisplayDebugMessage(stream_.str());
505 // Crash the process to generate a dump.
deanm@google.comc2b652a2008-08-13 20:15:11 +0900506 DebugUtil::BreakDebugger();
507 // TODO(mmentovai): when we have breakpad support, generate a breakpad
508 // dump, but until then, do not invoke the Apple crash reporter.
initial.commit3f4a7322008-07-27 06:49:38 +0900509 }
510 }
511 }
512}
513
514void CloseLogFile() {
515 if (!log_file)
516 return;
517
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900518 CloseFile(log_file);
initial.commit3f4a7322008-07-27 06:49:38 +0900519 log_file = NULL;
520}
521
522} // namespace logging
523
524std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
brettw@google.com7bea9d12008-08-07 12:11:42 +0900525 return out << base::SysWideToUTF8(std::wstring(wstr));
initial.commit3f4a7322008-07-27 06:49:38 +0900526}