blob: 27781ae0d1b3c1f7711b6d336bef6ca7a040b1b2 [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
ericroman@google.com1af64932008-08-12 03:08:22 +090030#include "base/notimplemented.h"
pinkerton@google.com56053fe2008-08-08 22:27:28 +090031#include "build/build_config.h"
32
33#if defined(WIN32)
34#include <windows.h>
35typedef HANDLE FileHandle;
36typedef HANDLE MutexHandle;
37#endif
38
39#if defined(OS_MACOSX)
40#include <CoreFoundation/CoreFoundation.h>
41#include <mach/mach.h>
42#include <mach/mach_time.h>
43#include <mach-o/dyld.h>
evanm@google.com4487dd72008-08-12 07:52:59 +090044#endif
45
46#if defined(OS_POSIX)
pinkerton@google.com56053fe2008-08-08 22:27:28 +090047#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <unistd.h>
51#define MAX_PATH PATH_MAX
52typedef FILE* FileHandle;
53typedef pthread_mutex_t* MutexHandle;
54#endif
55
initial.commit3f4a7322008-07-27 06:49:38 +090056#include <ctime>
57#include <iomanip>
58#include <cstring>
initial.commit3f4a7322008-07-27 06:49:38 +090059#include <algorithm>
60#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"
64#include "base/logging.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;
evanm@google.come41d3b32008-08-15 10:04:11 +090078#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +090079LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
evanm@google.come41d3b32008-08-15 10:04:11 +090080#elif defined(OS_POSIX)
81LoggingDestination logging_destination = LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG;
82#endif
initial.commit3f4a7322008-07-27 06:49:38 +090083
84const int kMaxFilteredLogLevel = LOG_WARNING;
evanm@google.com4487dd72008-08-12 07:52:59 +090085std::string* log_filter_prefix;
initial.commit3f4a7322008-07-27 06:49:38 +090086
evanm@google.com4487dd72008-08-12 07:52:59 +090087// Which log file to use? This is initialized by InitLogging or
initial.commit3f4a7322008-07-27 06:49:38 +090088// will be lazily initialized to the default value when it is
89// first needed.
pinkerton@google.com56053fe2008-08-08 22:27:28 +090090#if defined(OS_WIN)
91typedef wchar_t PathChar;
evanm@google.com4487dd72008-08-12 07:52:59 +090092typedef std::wstring PathString;
pinkerton@google.com56053fe2008-08-08 22:27:28 +090093#else
94typedef char PathChar;
evanm@google.com4487dd72008-08-12 07:52:59 +090095typedef std::string PathString;
pinkerton@google.com56053fe2008-08-08 22:27:28 +090096#endif
evanm@google.com4487dd72008-08-12 07:52:59 +090097PathString* log_file_name = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +090098
99// this file is lazily opened and the handle may be NULL
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900100FileHandle log_file = NULL;
initial.commit3f4a7322008-07-27 06:49:38 +0900101
102// what should be prepended to each message?
103bool log_process_id = false;
104bool log_thread_id = false;
105bool log_timestamp = true;
106bool log_tickcount = false;
107
108// An assert handler override specified by the client to be called instead of
109// the debug message dialog.
110LogAssertHandlerFunction log_assert_handler = NULL;
111
112// The lock is used if log file locking is false. It helps us avoid problems
113// with multiple threads writing to the log file at the same time. Use
114// LockImpl directly instead of using Lock, because Lock makes logging calls.
115static LockImpl* log_lock = NULL;
116
117// When we don't use a lock, we are using a global mutex. We need to do this
118// because LockFileEx is not thread safe.
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900119#if defined(OS_WIN)
120MutexHandle log_mutex = NULL;
121#elif defined(OS_POSIX)
122pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
123#endif
124
125// Helper functions to wrap platform differences.
126
127int32 CurrentProcessId() {
128#if defined(OS_WIN)
129 return GetCurrentProcessId();
130#elif defined(OS_POSIX)
131 return getpid();
132#endif
133}
134
135int32 CurrentThreadId() {
136#if defined(OS_WIN)
137 return GetCurrentThreadId();
138#elif defined(OS_MACOSX)
139 return mach_thread_self();
140#else
ericroman@google.com1af64932008-08-12 03:08:22 +0900141 NOTIMPLEMENTED();
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900142 return 0;
143#endif
144}
145
146uint64 TickCount() {
147#if defined(OS_WIN)
148 return GetTickCount();
149#elif defined(OS_MACOSX)
150 return mach_absolute_time();
151#else
ericroman@google.com1af64932008-08-12 03:08:22 +0900152 NOTIMPLEMENTED();
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900153 return 0;
154#endif
155}
156
157void CloseFile(FileHandle log) {
158#if defined(OS_WIN)
159 CloseHandle(log);
160#else
161 fclose(log);
162#endif
163}
164
evanm@google.com4487dd72008-08-12 07:52:59 +0900165void DeleteFilePath(const PathString& log_name) {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900166#if defined(OS_WIN)
evanm@google.com4487dd72008-08-12 07:52:59 +0900167 DeleteFile(log_name.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900168#else
evanm@google.com4487dd72008-08-12 07:52:59 +0900169 unlink(log_name.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900170#endif
171}
initial.commit3f4a7322008-07-27 06:49:38 +0900172
173// Called by logging functions to ensure that debug_file is initialized
174// and can be used for writing. Returns false if the file could not be
175// initialized. debug_file will be NULL in this case.
176bool InitializeLogFileHandle() {
177 if (log_file)
178 return true;
179
evanm@google.com4487dd72008-08-12 07:52:59 +0900180 if (!log_file_name) {
181 // Nobody has called InitLogging to specify a debug log file, so here we
182 // initialize the log file name to a default.
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900183#if defined(OS_WIN)
evanm@google.com4487dd72008-08-12 07:52:59 +0900184 // On Windows we use the same path as the exe.
185 wchar_t module_name[MAX_PATH];
186 GetModuleFileName(NULL, module_name, MAX_PATH);
187 log_file_name = new std::wstring(module_name);
188 std::wstring::size_type last_backslash =
189 log_file_name->rfind('\\', log_file_name->size());
190 if (last_backslash != std::wstring::npos)
191 log_file_name->erase(last_backslash + 1);
192 *log_file_name += L"debug.log";
193#elif defined(OS_POSIX)
194 // On other platforms we just use the current directory.
195 log_file_name = new std::string("debug.log");
196#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900197 }
198
evanm@google.com4487dd72008-08-12 07:52:59 +0900199#if defined(OS_WIN)
200 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
initial.commit3f4a7322008-07-27 06:49:38 +0900201 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
202 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
203 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
204 // try the current directory
205 log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
206 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
207 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
208 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
209 log_file = NULL;
210 return false;
211 }
212 }
213 SetFilePointer(log_file, 0, 0, FILE_END);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900214#elif defined(OS_POSIX)
evanm@google.com4487dd72008-08-12 07:52:59 +0900215 log_file = fopen(log_file_name->c_str(), "a");
216 if (log_file == NULL)
217 return false;
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900218#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900219 return true;
220}
221
222void InitLogMutex() {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900223#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900224 if (!log_mutex) {
225 // \ is not a legal character in mutex names so we replace \ with /
evanm@google.com4487dd72008-08-12 07:52:59 +0900226 std::wstring safe_name(*log_file_name);
initial.commit3f4a7322008-07-27 06:49:38 +0900227 std::replace(safe_name.begin(), safe_name.end(), '\\', '/');
228 std::wstring t(L"Global\\");
229 t.append(safe_name);
230 log_mutex = ::CreateMutex(NULL, FALSE, t.c_str());
231 }
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900232#elif defined(OS_POSIX)
233 // statically initialized
234#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900235}
236
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900237void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
initial.commit3f4a7322008-07-27 06:49:38 +0900238 LogLockingState lock_log, OldFileDeletionState delete_old) {
239 g_enable_dcheck = CommandLine().HasSwitch(switches::kEnableDCHECK);
240
241 if (log_file) {
242 // calling InitLogging twice or after some log call has already opened the
243 // default log file will re-initialize to the new options
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900244 CloseFile(log_file);
initial.commit3f4a7322008-07-27 06:49:38 +0900245 log_file = NULL;
246 }
247
248 lock_log_file = lock_log;
249 logging_destination = logging_dest;
250
251 // ignore file options if logging is disabled or only to system
252 if (logging_destination == LOG_NONE ||
253 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
254 return;
255
evanm@google.com4487dd72008-08-12 07:52:59 +0900256 if (!log_file_name)
257 log_file_name = new PathString();
258 *log_file_name = new_log_file;
initial.commit3f4a7322008-07-27 06:49:38 +0900259 if (delete_old == DELETE_OLD_LOG_FILE)
evanm@google.com4487dd72008-08-12 07:52:59 +0900260 DeleteFilePath(*log_file_name);
initial.commit3f4a7322008-07-27 06:49:38 +0900261
262 if (lock_log_file == LOCK_LOG_FILE) {
263 InitLogMutex();
264 } else if (!log_lock) {
265 log_lock = new LockImpl();
266 }
267
268 InitializeLogFileHandle();
269}
270
271void SetMinLogLevel(int level) {
272 min_log_level = level;
273}
274
275int GetMinLogLevel() {
276 return min_log_level;
277}
278
279void SetLogFilterPrefix(const char* filter) {
280 if (log_filter_prefix) {
evanm@google.com4487dd72008-08-12 07:52:59 +0900281 delete log_filter_prefix;
initial.commit3f4a7322008-07-27 06:49:38 +0900282 log_filter_prefix = NULL;
283 }
284
evanm@google.com4487dd72008-08-12 07:52:59 +0900285 if (filter)
286 log_filter_prefix = new std::string(filter);
initial.commit3f4a7322008-07-27 06:49:38 +0900287}
288
289void SetLogItems(bool enable_process_id, bool enable_thread_id,
290 bool enable_timestamp, bool enable_tickcount) {
291 log_process_id = enable_process_id;
292 log_thread_id = enable_thread_id;
293 log_timestamp = enable_timestamp;
294 log_tickcount = enable_tickcount;
295}
296
297void SetLogAssertHandler(LogAssertHandlerFunction handler) {
298 log_assert_handler = handler;
299}
300
301// 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
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900312#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900313 // 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
brettw@google.com7bea9d12008-08-07 12:11:42 +0900321 // 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.commit3f4a7322008-07-27 06:49:38 +0900325
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;
brettw@google.com7bea9d12008-08-07 12:11:42 +0900331 if (CreateProcessW(prog_name, cmdline, NULL, NULL, false, 0, NULL,
initial.commit3f4a7322008-07-27 06:49:38 +0900332 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
brettw@google.com7bea9d12008-08-07 12:11:42 +0900338 MessageBoxW(NULL, cmdline, L"Fatal error",
initial.commit3f4a7322008-07-27 06:49:38 +0900339 MB_OK | MB_ICONHAND | MB_TOPMOST);
340 }
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900341#else
342 fprintf(stderr, "%s\n", str.c_str());
343#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900344}
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
358LogMessage::LogMessage(const char* file, int line)
359 : severity_(LOG_INFO) {
360 Init(file, line);
361}
362
363LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
364 : severity_(severity) {
365 Init(file, line);
366}
367
368// writes the common header info to the stream
369void LogMessage::Init(const char* file, int line) {
370 // log only the filename
371 const char* last_slash = strrchr(file, '\\');
372 if (last_slash)
373 file = last_slash + 1;
374
375 // TODO(darin): It might be nice if the columns were fixed width.
376
377 stream_ << '[';
378 if (log_process_id)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900379 stream_ << CurrentProcessId() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900380 if (log_thread_id)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900381 stream_ << CurrentThreadId() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900382 if (log_timestamp) {
383 time_t t = time(NULL);
384#if _MSC_VER >= 1400
385 struct tm local_time = {0};
386 localtime_s(&local_time, &t);
387 struct tm* tm_time = &local_time;
388#else
389 struct tm* tm_time = localtime(&t);
390#endif
391 stream_ << std::setfill('0')
392 << std::setw(2) << 1 + tm_time->tm_mon
393 << std::setw(2) << tm_time->tm_mday
394 << '/'
395 << std::setw(2) << tm_time->tm_hour
396 << std::setw(2) << tm_time->tm_min
397 << std::setw(2) << tm_time->tm_sec
398 << ':';
399 }
400 if (log_tickcount)
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900401 stream_ << TickCount() << ':';
initial.commit3f4a7322008-07-27 06:49:38 +0900402 stream_ << log_severity_names[severity_] << ":" << file << "(" << line << ")] ";
403
404 message_start_ = stream_.tellp();
405}
406
407LogMessage::~LogMessage() {
408 // TODO(brettw) modify the macros so that nothing is executed when the log
409 // level is too high.
410 if (severity_ < min_log_level)
411 return;
412
413 std::string str_newline(stream_.str());
414 str_newline.append("\r\n");
415
416 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
evanm@google.com4487dd72008-08-12 07:52:59 +0900417 str_newline.compare(message_start_, log_filter_prefix->size(),
418 log_filter_prefix->data()) != 0) {
initial.commit3f4a7322008-07-27 06:49:38 +0900419 return;
420 }
421
422 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900423 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
424#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900425 OutputDebugStringA(str_newline.c_str());
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900426#else
427 fprintf(stderr, str_newline.c_str());
428#endif
429 }
430
initial.commit3f4a7322008-07-27 06:49:38 +0900431 // write to log file
432 if (logging_destination != LOG_NONE &&
433 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
434 InitializeLogFileHandle()) {
435 // we can have multiple threads and/or processes, so try to prevent them from
436 // clobbering each other's writes
437 if (lock_log_file == LOCK_LOG_FILE) {
438 // Ensure that the mutex is initialized in case the client app did not
439 // call InitLogging. This is not thread safe. See below
440 InitLogMutex();
441
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900442#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900443 DWORD r = ::WaitForSingleObject(log_mutex, INFINITE);
444 DCHECK(r != WAIT_ABANDONED);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900445#elif defined(OS_POSIX)
446 pthread_mutex_lock(&log_mutex);
447#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900448 } else {
449 // use the lock
450 if (!log_lock) {
451 // The client app did not call InitLogging, and so the lock has not
452 // been created. We do this on demand, but if two threads try to do
453 // this at the same time, there will be a race condition to create
454 // the lock. This is why InitLogging should be called from the main
455 // thread at the beginning of execution.
456 log_lock = new LockImpl();
457 }
458 log_lock->Lock();
459 }
460
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900461#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900462 SetFilePointer(log_file, 0, 0, SEEK_END);
463 DWORD num_written;
464 WriteFile(log_file, (void*)str_newline.c_str(), (DWORD)str_newline.length(), &num_written, NULL);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900465#else
466 fprintf(log_file, "%s", str_newline.c_str());
467#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900468
469 if (lock_log_file == LOCK_LOG_FILE) {
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900470#if defined(OS_WIN)
initial.commit3f4a7322008-07-27 06:49:38 +0900471 ReleaseMutex(log_mutex);
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900472#elif defined(OS_POSIX)
473 pthread_mutex_unlock(&log_mutex);
474#endif
initial.commit3f4a7322008-07-27 06:49:38 +0900475 } else {
476 log_lock->Unlock();
477 }
478 }
479
480 if (severity_ == LOG_FATAL) {
481 // display a message or break into the debugger on a fatal error
deanm@google.comc2b652a2008-08-13 20:15:11 +0900482 if (DebugUtil::BeingDebugged()) {
483 DebugUtil::BreakDebugger();
484 } else {
initial.commit3f4a7322008-07-27 06:49:38 +0900485 if (log_assert_handler) {
486 // make a copy of the string for the handler out of paranoia
487 log_assert_handler(std::string(stream_.str()));
488 } else {
489 // don't use the string with the newline, get a fresh version to send to
490 // the debug message process
491 DisplayDebugMessage(stream_.str());
492 // Crash the process to generate a dump.
deanm@google.comc2b652a2008-08-13 20:15:11 +0900493 DebugUtil::BreakDebugger();
494 // TODO(mmentovai): when we have breakpad support, generate a breakpad
495 // dump, but until then, do not invoke the Apple crash reporter.
initial.commit3f4a7322008-07-27 06:49:38 +0900496 }
497 }
498 }
499}
500
501void CloseLogFile() {
502 if (!log_file)
503 return;
504
pinkerton@google.com56053fe2008-08-08 22:27:28 +0900505 CloseFile(log_file);
initial.commit3f4a7322008-07-27 06:49:38 +0900506 log_file = NULL;
507}
508
509} // namespace logging
510
511std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
brettw@google.com7bea9d12008-08-07 12:11:42 +0900512 return out << base::SysWideToUTF8(std::wstring(wstr));
initial.commit3f4a7322008-07-27 06:49:38 +0900513}