blob: 8a23247857427abd372d1a6f1a979466ba3c53ba [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// 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.commit3f4a7322008-07-27 06:49:38 +09004
darin@google.com12d40bb2008-08-20 03:36:23 +09005#include "base/logging.h"
pinkerton@google.com56053fe2008-08-08 22:27:28 +09006
darin@google.com12d40bb2008-08-20 03:36:23 +09007#if defined(OS_WIN)
pinkerton@google.com56053fe2008-08-08 22:27:28 +09008#include <windows.h>
9typedef HANDLE FileHandle;
10typedef HANDLE MutexHandle;
11#endif
12
13#if defined(OS_MACOSX)
14#include <CoreFoundation/CoreFoundation.h>
15#include <mach/mach.h>
16#include <mach/mach_time.h>
17#include <mach-o/dyld.h>
evanm@google.com4487dd72008-08-12 07:52:59 +090018#endif
19
20#if defined(OS_POSIX)
pinkerton@google.com56053fe2008-08-08 22:27:28 +090021#include <stdlib.h>
22#include <stdio.h>
23#include <string.h>
24#include <unistd.h>
25#define MAX_PATH PATH_MAX
26typedef FILE* FileHandle;
27typedef pthread_mutex_t* MutexHandle;
28#endif
29
initial.commit3f4a7322008-07-27 06:49:38 +090030#include <ctime>
31#include <iomanip>
32#include <cstring>
initial.commit3f4a7322008-07-27 06:49:38 +090033#include <algorithm>
darin@google.com12d40bb2008-08-20 03:36:23 +090034
initial.commit3f4a7322008-07-27 06:49:38 +090035#include "base/base_switches.h"
36#include "base/command_line.h"
deanm@google.comc2b652a2008-08-13 20:15:11 +090037#include "base/debug_util.h"
initial.commit3f4a7322008-07-27 06:49:38 +090038#include "base/lock_impl.h"
darin@google.com12d40bb2008-08-20 03:36:23 +090039#include "base/notimplemented.h"
deanm@google.coma65ec9f2008-08-19 22:19:24 +090040#include "base/string_piece.h"
pinkerton@google.com56053fe2008-08-08 22:27:28 +090041#include "base/string_util.h"
brettw@google.com7bea9d12008-08-07 12:11:42 +090042#include "base/sys_string_conversions.h"
pinkerton@google.com56053fe2008-08-08 22:27:28 +090043
initial.commit3f4a7322008-07-27 06:49:38 +090044namespace logging {
45
46bool g_enable_dcheck = false;
47
48const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
49 "INFO", "WARNING", "ERROR", "FATAL" };
50
51int min_log_level = 0;
52LogLockingState lock_log_file = LOCK_LOG_FILE;
mmentovai@google.comf0944f32008-08-20 08:39:32 +090053
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.
evanm@google.come41d3b32008-08-15 10:04:11 +090058#if defined(OS_WIN)
mmentovai@google.com0f8dd7e2008-08-23 02:09:34 +090059LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
evanm@google.come41d3b32008-08-15 10:04:11 +090060#elif defined(OS_POSIX)
mmentovai@google.comf0944f32008-08-20 08:39:32 +090061LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
evanm@google.come41d3b32008-08-15 10:04:11 +090062#endif
initial.commit3f4a7322008-07-27 06:49:38 +090063
64const int kMaxFilteredLogLevel = LOG_WARNING;
evanm@google.com4487dd72008-08-12 07:52:59 +090065std::string* log_filter_prefix;
initial.commit3f4a7322008-07-27 06:49:38 +090066
evanm@google.com4487dd72008-08-12 07:52:59 +090067// Which log file to use? This is initialized by InitLogging or
initial.commit3f4a7322008-07-27 06:49:38 +090068// will be lazily initialized to the default value when it is
69// first needed.
pinkerton@google.com56053fe2008-08-08 22:27:28 +090070#if defined(OS_WIN)
71typedef wchar_t PathChar;
evanm@google.com4487dd72008-08-12 07:52:59 +090072typedef std::wstring PathString;
pinkerton@google.com56053fe2008-08-08 22:27:28 +090073#else
74typedef char PathChar;
evanm@google.com4487dd72008-08-12 07:52:59 +090075typedef std::string PathString;
pinkerton@google.com56053fe2008-08-08 22:27:28 +090076#endif
evanm@google.com4487dd72008-08-12 07:52:59 +090077PathString* log_file_name = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +090078
79// this file is lazily opened and the handle may be NULL
pinkerton@google.com56053fe2008-08-08 22:27:28 +090080FileHandle log_file = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +090081
82// what should be prepended to each message?
83bool log_process_id = false;
84bool log_thread_id = false;
85bool log_timestamp = true;
86bool log_tickcount = false;
87
88// An assert handler override specified by the client to be called instead of
89// the debug message dialog.
90LogAssertHandlerFunction log_assert_handler = NULL;
91
92// The lock is used if log file locking is false. It helps us avoid problems
93// with multiple threads writing to the log file at the same time. Use
94// LockImpl directly instead of using Lock, because Lock makes logging calls.
95static LockImpl* log_lock = NULL;
96
97// When we don't use a lock, we are using a global mutex. We need to do this
98// because LockFileEx is not thread safe.
pinkerton@google.com56053fe2008-08-08 22:27:28 +090099#if defined(OS_WIN)
100MutexHandle log_mutex = NULL;
101#elif defined(OS_POSIX)
102pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
103#endif
104
105// Helper functions to wrap platform differences.
106
107int32 CurrentProcessId() {
108#if defined(OS_WIN)
109 return GetCurrentProcessId();
110#elif defined(OS_POSIX)
111 return getpid();
112#endif
113}
114
115int32 CurrentThreadId() {
116#if defined(OS_WIN)
117 return GetCurrentThreadId();
118#elif defined(OS_MACOSX)
119 return mach_thread_self();
120#else
ericroman@google.com1af64932008-08-12 03:08:22 +0900121 NOTIMPLEMENTED();
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900122 return 0;
123#endif
124}
125
126uint64 TickCount() {
127#if defined(OS_WIN)
128 return GetTickCount();
129#elif defined(OS_MACOSX)
130 return mach_absolute_time();
131#else
ericroman@google.com1af64932008-08-12 03:08:22 +0900132 NOTIMPLEMENTED();
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900133 return 0;
134#endif
135}
136
137void CloseFile(FileHandle log) {
138#if defined(OS_WIN)
139 CloseHandle(log);
140#else
141 fclose(log);
142#endif
143}
144
evanm@google.com4487dd72008-08-12 07:52:59 +0900145void DeleteFilePath(const PathString& log_name) {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900146#if defined(OS_WIN)
evanm@google.com4487dd72008-08-12 07:52:59 +0900147 DeleteFile(log_name.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900148#else
evanm@google.com4487dd72008-08-12 07:52:59 +0900149 unlink(log_name.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900150#endif
151}
initial.commit3f4a7322008-07-27 06:49:38 +0900152
153// Called by logging functions to ensure that debug_file is initialized
154// and can be used for writing. Returns false if the file could not be
155// initialized. debug_file will be NULL in this case.
156bool InitializeLogFileHandle() {
157 if (log_file)
158 return true;
159
evanm@google.com4487dd72008-08-12 07:52:59 +0900160 if (!log_file_name) {
161 // Nobody has called InitLogging to specify a debug log file, so here we
162 // initialize the log file name to a default.
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900163#if defined(OS_WIN)
evanm@google.com4487dd72008-08-12 07:52:59 +0900164 // On Windows we use the same path as the exe.
165 wchar_t module_name[MAX_PATH];
166 GetModuleFileName(NULL, module_name, MAX_PATH);
167 log_file_name = new std::wstring(module_name);
168 std::wstring::size_type last_backslash =
169 log_file_name->rfind('\\', log_file_name->size());
170 if (last_backslash != std::wstring::npos)
171 log_file_name->erase(last_backslash + 1);
172 *log_file_name += L"debug.log";
173#elif defined(OS_POSIX)
174 // On other platforms we just use the current directory.
175 log_file_name = new std::string("debug.log");
176#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900177 }
178
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900179 if (logging_destination == LOG_ONLY_TO_FILE ||
180 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
evanm@google.com4487dd72008-08-12 07:52:59 +0900181#if defined(OS_WIN)
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900182 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
initial.commit3f4a7322008-07-27 06:49:38 +0900183 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
184 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
185 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900186 // try the current directory
187 log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
188 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
189 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
190 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
191 log_file = NULL;
192 return false;
193 }
initial.commit3f4a7322008-07-27 06:49:38 +0900194 }
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900195 SetFilePointer(log_file, 0, 0, FILE_END);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900196#elif defined(OS_POSIX)
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900197 log_file = fopen(log_file_name->c_str(), "a");
198 if (log_file == NULL)
199 return false;
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900200#endif
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900201 }
202
initial.commit3f4a7322008-07-27 06:49:38 +0900203 return true;
204}
205
206void InitLogMutex() {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900207#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900208 if (!log_mutex) {
209 // \ is not a legal character in mutex names so we replace \ with /
evanm@google.com4487dd72008-08-12 07:52:59 +0900210 std::wstring safe_name(*log_file_name);
initial.commit3f4a7322008-07-27 06:49:38 +0900211 std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
212 std::wstring t(L"Global\\");
213 t.append(safe_name);
214 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
215 }
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900216#elif defined(OS_POSIX)
217 // statically initialized
218#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900219}
220
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900221void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
initial.commit3f4a7322008-07-27 06:49:38 +0900222 LogLockingState lock_log, OldFileDeletionState delete_old) {
223 g_enable_dcheck = CommandLine().HasSwitch(switches::kEnableDCHECK);
224
225 if (log_file) {
226 // calling InitLogging twice or after some log call has already opened the
227 // default log file will re-initialize to the new options
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900228 CloseFile(log_file);
initial.commit3f4a7322008-07-27 06:49:38 +0900229 log_file = NULL;
230 }
231
232 lock_log_file = lock_log;
233 logging_destination = logging_dest;
234
235 // ignore file options if logging is disabled or only to system
236 if (logging_destination == LOG_NONE ||
237 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
238 return;
239
evanm@google.com4487dd72008-08-12 07:52:59 +0900240 if (!log_file_name)
241 log_file_name = new PathString();
242 *log_file_name = new_log_file;
initial.commit3f4a7322008-07-27 06:49:38 +0900243 if (delete_old == DELETE_OLD_LOG_FILE)
evanm@google.com4487dd72008-08-12 07:52:59 +0900244 DeleteFilePath(*log_file_name);
initial.commit3f4a7322008-07-27 06:49:38 +0900245
246 if (lock_log_file == LOCK_LOG_FILE) {
247 InitLogMutex();
248 } else if (!log_lock) {
249 log_lock = new LockImpl();
250 }
251
252 InitializeLogFileHandle();
253}
254
255void SetMinLogLevel(int level) {
256 min_log_level = level;
257}
258
259int GetMinLogLevel() {
260 return min_log_level;
261}
262
263void SetLogFilterPrefix(const char* filter) {
264 if (log_filter_prefix) {
evanm@google.com4487dd72008-08-12 07:52:59 +0900265 delete log_filter_prefix;
initial.commit3f4a7322008-07-27 06:49:38 +0900266 log_filter_prefix = NULL;
267 }
268
evanm@google.com4487dd72008-08-12 07:52:59 +0900269 if (filter)
270 log_filter_prefix = new std::string(filter);
initial.commit3f4a7322008-07-27 06:49:38 +0900271}
272
273void SetLogItems(bool enable_process_id, bool enable_thread_id,
274 bool enable_timestamp, bool enable_tickcount) {
275 log_process_id = enable_process_id;
276 log_thread_id = enable_thread_id;
277 log_timestamp = enable_timestamp;
278 log_tickcount = enable_tickcount;
279}
280
281void SetLogAssertHandler(LogAssertHandlerFunction handler) {
282 log_assert_handler = handler;
283}
284
285// Displays a message box to the user with the error message in it. For
286// Windows programs, it's possible that the message loop is messed up on
287// a fatal error, and creating a MessageBox will cause that message loop
288// to be run. Instead, we try to spawn another process that displays its
289// command line. We look for "Debug Message.exe" in the same directory as
290// the application. If it exists, we use it, otherwise, we use a regular
291// message box.
292void DisplayDebugMessage(const std::string& str) {
293 if (str.empty())
294 return;
295
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900296#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900297 // look for the debug dialog program next to our application
298 wchar_t prog_name[MAX_PATH];
299 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
300 wchar_t* backslash = wcsrchr(prog_name, '\\');
301 if (backslash)
302 backslash[1] = 0;
303 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
304
brettw@google.com7bea9d12008-08-07 12:11:42 +0900305 // Stupid CreateProcess requires a non-const command line and may modify it.
306 // We also want to use the wide string.
307 std::wstring cmdline_string = base::SysUTF8ToWide(str);
308 wchar_t* cmdline = const_cast<wchar_t*>(cmdline_string.c_str());
initial.commit3f4a7322008-07-27 06:49:38 +0900309
310 STARTUPINFO startup_info;
311 memset(&startup_info, 0, sizeof(startup_info));
312 startup_info.cb = sizeof(startup_info);
313
314 PROCESS_INFORMATION process_info;
brettw@google.com7bea9d12008-08-07 12:11:42 +0900315 if (CreateProcessW(prog_name, cmdline, NULL, NULL, false, 0, NULL,
initial.commit3f4a7322008-07-27 06:49:38 +0900316 NULL, &startup_info, &process_info)) {
317 WaitForSingleObject(process_info.hProcess, INFINITE);
318 CloseHandle(process_info.hThread);
319 CloseHandle(process_info.hProcess);
320 } else {
321 // debug process broken, let's just do a message box
brettw@google.com7bea9d12008-08-07 12:11:42 +0900322 MessageBoxW(NULL, cmdline, L"Fatal error",
initial.commit3f4a7322008-07-27 06:49:38 +0900323 MB_OK | MB_ICONHAND | MB_TOPMOST);
324 }
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900325#else
326 fprintf(stderr, "%s\n", str.c_str());
327#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900328}
329
330LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
331 int ctr)
332 : severity_(severity) {
333 Init(file, line);
334}
335
336LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
337 : severity_(LOG_FATAL) {
338 Init(file, line);
339 stream_ << "Check failed: " << (*result.str_);
340}
341
342LogMessage::LogMessage(const char* file, int line)
343 : severity_(LOG_INFO) {
344 Init(file, line);
345}
346
347LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
348 : severity_(severity) {
349 Init(file, line);
350}
351
352// writes the common header info to the stream
353void LogMessage::Init(const char* file, int line) {
354 // log only the filename
355 const char* last_slash = strrchr(file, '\\');
356 if (last_slash)
357 file = last_slash + 1;
358
359 // TODO(darin): It might be nice if the columns were fixed width.
360
361 stream_ << '[';
362 if (log_process_id)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900363 stream_ << CurrentProcessId() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900364 if (log_thread_id)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900365 stream_ << CurrentThreadId() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900366 if (log_timestamp) {
367 time_t t = time(NULL);
368#if _MSC_VER >= 1400
369 struct tm local_time = {0};
370 localtime_s(&local_time, &t);
371 struct tm* tm_time = &local_time;
372#else
373 struct tm* tm_time = localtime(&t);
374#endif
375 stream_ << std::setfill('0')
376 << std::setw(2) << 1 + tm_time->tm_mon
377 << std::setw(2) << tm_time->tm_mday
378 << '/'
379 << std::setw(2) << tm_time->tm_hour
380 << std::setw(2) << tm_time->tm_min
381 << std::setw(2) << tm_time->tm_sec
382 << ':';
383 }
384 if (log_tickcount)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900385 stream_ << TickCount() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900386 stream_ << log_severity_names[severity_] << ":" << file << "(" << line << ")] ";
387
388 message_start_ = stream_.tellp();
389}
390
391LogMessage::~LogMessage() {
392 // TODO(brettw) modify the macros so that nothing is executed when the log
393 // level is too high.
394 if (severity_ < min_log_level)
395 return;
396
397 std::string str_newline(stream_.str());
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900398#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900399 str_newline.append("\r\n");
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900400#else
401 str_newline.append("\n");
402#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900403
404 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
evanm@google.com4487dd72008-08-12 07:52:59 +0900405 str_newline.compare(message_start_, log_filter_prefix->size(),
406 log_filter_prefix->data()) != 0) {
initial.commit3f4a7322008-07-27 06:49:38 +0900407 return;
408 }
409
410 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900411 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
412#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900413 OutputDebugStringA(str_newline.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900414#else
mmentovai@google.comf0944f32008-08-20 08:39:32 +0900415 fprintf(stderr, "%s", str_newline.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900416#endif
417 }
418
initial.commit3f4a7322008-07-27 06:49:38 +0900419 // write to log file
420 if (logging_destination != LOG_NONE &&
421 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
422 InitializeLogFileHandle()) {
423 // we can have multiple threads and/or processes, so try to prevent them from
424 // clobbering each other's writes
425 if (lock_log_file == LOCK_LOG_FILE) {
426 // Ensure that the mutex is initialized in case the client app did not
427 // call InitLogging. This is not thread safe. See below
428 InitLogMutex();
429
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900430#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900431 DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
432 DCHECK(r != WAIT_ABANDONED);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900433#elif defined(OS_POSIX)
434 pthread_mutex_lock(&log_mutex);
435#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900436 } else {
437 // use the lock
438 if (!log_lock) {
439 // The client app did not call InitLogging, and so the lock has not
440 // been created. We do this on demand, but if two threads try to do
441 // this at the same time, there will be a race condition to create
442 // the lock. This is why InitLogging should be called from the main
443 // thread at the beginning of execution.
444 log_lock = new LockImpl();
445 }
446 log_lock->Lock();
447 }
448
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900449#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900450 SetFilePointer(log_file, 0, 0, SEEK_END);
451 DWORD num_written;
452 WriteFile(log_file, (void*)str_newline.c_str(), (DWORD)str_newline.length(), &num_written, NULL);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900453#else
454 fprintf(log_file, "%s", str_newline.c_str());
455#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900456
457 if (lock_log_file == LOCK_LOG_FILE) {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900458#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900459 ReleaseMutex(log_mutex);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900460#elif defined(OS_POSIX)
461 pthread_mutex_unlock(&log_mutex);
462#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900463 } else {
464 log_lock->Unlock();
465 }
466 }
467
468 if (severity_ == LOG_FATAL) {
469 // display a message or break into the debugger on a fatal error
deanm@google.comc2b652a2008-08-13 20:15:11 +0900470 if (DebugUtil::BeingDebugged()) {
471 DebugUtil::BreakDebugger();
472 } else {
initial.commit3f4a7322008-07-27 06:49:38 +0900473 if (log_assert_handler) {
474 // make a copy of the string for the handler out of paranoia
475 log_assert_handler(std::string(stream_.str()));
476 } else {
477 // don't use the string with the newline, get a fresh version to send to
478 // the debug message process
479 DisplayDebugMessage(stream_.str());
480 // Crash the process to generate a dump.
deanm@google.comc2b652a2008-08-13 20:15:11 +0900481 DebugUtil::BreakDebugger();
482 // TODO(mmentovai): when we have breakpad support, generate a breakpad
483 // dump, but until then, do not invoke the Apple crash reporter.
initial.commit3f4a7322008-07-27 06:49:38 +0900484 }
485 }
486 }
487}
488
489void CloseLogFile() {
490 if (!log_file)
491 return;
492
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900493 CloseFile(log_file);
initial.commit3f4a7322008-07-27 06:49:38 +0900494 log_file = NULL;
495}
496
497} // namespace logging
498
499std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
brettw@google.com7bea9d12008-08-07 12:11:42 +0900500 return out << base::SysWideToUTF8(std::wstring(wstr));
initial.commit3f4a7322008-07-27 06:49:38 +0900501}
license.botf003cfe2008-08-24 09:55:55 +0900502