blob: b59e3fbc4f6444417fc9dfdcf44861349dea80de [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]d8617a62009-10-09 23:52:2022#include <errno.h>
[email protected]f6abeba2008-08-08 13:27:2823#include <stdlib.h>
24#include <stdio.h>
25#include <string.h>
26#include <unistd.h>
27#define MAX_PATH PATH_MAX
28typedef FILE* FileHandle;
29typedef pthread_mutex_t* MutexHandle;
30#endif
31
initial.commitd7cae122008-07-26 21:49:3832#include <ctime>
33#include <iomanip>
34#include <cstring>
initial.commitd7cae122008-07-26 21:49:3835#include <algorithm>
[email protected]b16ef312008-08-19 18:36:2336
initial.commitd7cae122008-07-26 21:49:3837#include "base/base_switches.h"
38#include "base/command_line.h"
[email protected]1ffe08c12008-08-13 11:15:1139#include "base/debug_util.h"
initial.commitd7cae122008-07-26 21:49:3840#include "base/lock_impl.h"
[email protected]d8617a62009-10-09 23:52:2041#if defined(OS_POSIX)
42#include "base/safe_strerror_posix.h"
43#endif
[email protected]4bdaceb42008-08-19 13:19:2444#include "base/string_piece.h"
[email protected]f6abeba2008-08-08 13:27:2845#include "base/string_util.h"
[email protected]047a03f2009-10-07 02:10:2046#include "base/utf_string_conversions.h"
[email protected]52a261f2009-03-03 15:01:1247
initial.commitd7cae122008-07-26 21:49:3848namespace logging {
49
50bool g_enable_dcheck = false;
51
52const char* const log_severity_names[LOG_NUM_SEVERITIES] = {
[email protected]fb62a532009-02-12 01:19:0553 "INFO", "WARNING", "ERROR", "ERROR_REPORT", "FATAL" };
initial.commitd7cae122008-07-26 21:49:3854
55int min_log_level = 0;
56LogLockingState lock_log_file = LOCK_LOG_FILE;
[email protected]1d8c2702008-08-19 23:39:3257
58// The default set here for logging_destination will only be used if
59// InitLogging is not called. On Windows, use a file next to the exe;
60// on POSIX platforms, where it may not even be possible to locate the
61// executable on disk, use stderr.
[email protected]4c0040c2008-08-15 01:04:1162#if defined(OS_WIN)
[email protected]fe613522008-08-22 17:09:3463LoggingDestination logging_destination = LOG_ONLY_TO_FILE;
[email protected]4c0040c2008-08-15 01:04:1164#elif defined(OS_POSIX)
[email protected]1d8c2702008-08-19 23:39:3265LoggingDestination logging_destination = LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
[email protected]4c0040c2008-08-15 01:04:1166#endif
initial.commitd7cae122008-07-26 21:49:3867
68const int kMaxFilteredLogLevel = LOG_WARNING;
[email protected]614e9fa2008-08-11 22:52:5969std::string* log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:3870
[email protected]a33c9892008-08-25 20:10:3171// For LOG_ERROR and above, always print to stderr.
72const int kAlwaysPrintErrorLevel = LOG_ERROR;
73
[email protected]614e9fa2008-08-11 22:52:5974// Which log file to use? This is initialized by InitLogging or
initial.commitd7cae122008-07-26 21:49:3875// will be lazily initialized to the default value when it is
76// first needed.
[email protected]f6abeba2008-08-08 13:27:2877#if defined(OS_WIN)
78typedef wchar_t PathChar;
[email protected]614e9fa2008-08-11 22:52:5979typedef std::wstring PathString;
[email protected]f6abeba2008-08-08 13:27:2880#else
81typedef char PathChar;
[email protected]614e9fa2008-08-11 22:52:5982typedef std::string PathString;
[email protected]f6abeba2008-08-08 13:27:2883#endif
[email protected]614e9fa2008-08-11 22:52:5984PathString* log_file_name = NULL;
initial.commitd7cae122008-07-26 21:49:3885
86// this file is lazily opened and the handle may be NULL
[email protected]f6abeba2008-08-08 13:27:2887FileHandle log_file = NULL;
initial.commitd7cae122008-07-26 21:49:3888
89// what should be prepended to each message?
90bool log_process_id = false;
91bool log_thread_id = false;
92bool log_timestamp = true;
93bool log_tickcount = false;
94
95// An assert handler override specified by the client to be called instead of
[email protected]fb62a532009-02-12 01:19:0596// the debug message dialog and process termination.
initial.commitd7cae122008-07-26 21:49:3897LogAssertHandlerFunction log_assert_handler = NULL;
[email protected]fb62a532009-02-12 01:19:0598// An report handler override specified by the client to be called instead of
99// the debug message dialog.
100LogReportHandlerFunction log_report_handler = NULL;
initial.commitd7cae122008-07-26 21:49:38101
102// The lock is used if log file locking is false. It helps us avoid problems
103// with multiple threads writing to the log file at the same time. Use
104// LockImpl directly instead of using Lock, because Lock makes logging calls.
105static LockImpl* log_lock = NULL;
106
107// When we don't use a lock, we are using a global mutex. We need to do this
108// because LockFileEx is not thread safe.
[email protected]f6abeba2008-08-08 13:27:28109#if defined(OS_WIN)
110MutexHandle log_mutex = NULL;
111#elif defined(OS_POSIX)
112pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
113#endif
114
115// Helper functions to wrap platform differences.
116
[email protected]f8588472008-11-05 23:17:24117int32 CurrentProcessId() {
118#if defined(OS_WIN)
119 return GetCurrentProcessId();
120#elif defined(OS_POSIX)
121 return getpid();
122#endif
123}
124
125int32 CurrentThreadId() {
126#if defined(OS_WIN)
127 return GetCurrentThreadId();
128#elif defined(OS_MACOSX)
129 return mach_thread_self();
[email protected]052f1b52008-11-06 21:43:07130#elif defined(OS_LINUX)
131 return syscall(__NR_gettid);
[email protected]f8588472008-11-05 23:17:24132#endif
133}
134
135uint64 TickCount() {
136#if defined(OS_WIN)
137 return GetTickCount();
138#elif defined(OS_MACOSX)
139 return mach_absolute_time();
[email protected]052f1b52008-11-06 21:43:07140#elif defined(OS_LINUX)
141 struct timespec ts;
142 clock_gettime(CLOCK_MONOTONIC, &ts);
143
144 uint64 absolute_micro =
145 static_cast<int64>(ts.tv_sec) * 1000000 +
146 static_cast<int64>(ts.tv_nsec) / 1000;
147
148 return absolute_micro;
[email protected]f8588472008-11-05 23:17:24149#endif
150}
151
[email protected]f6abeba2008-08-08 13:27:28152void CloseFile(FileHandle log) {
153#if defined(OS_WIN)
154 CloseHandle(log);
155#else
156 fclose(log);
157#endif
158}
159
[email protected]614e9fa2008-08-11 22:52:59160void DeleteFilePath(const PathString& log_name) {
[email protected]f6abeba2008-08-08 13:27:28161#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:59162 DeleteFile(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28163#else
[email protected]614e9fa2008-08-11 22:52:59164 unlink(log_name.c_str());
[email protected]f6abeba2008-08-08 13:27:28165#endif
166}
initial.commitd7cae122008-07-26 21:49:38167
168// Called by logging functions to ensure that debug_file is initialized
169// and can be used for writing. Returns false if the file could not be
170// initialized. debug_file will be NULL in this case.
171bool InitializeLogFileHandle() {
172 if (log_file)
173 return true;
174
[email protected]614e9fa2008-08-11 22:52:59175 if (!log_file_name) {
176 // Nobody has called InitLogging to specify a debug log file, so here we
177 // initialize the log file name to a default.
[email protected]f6abeba2008-08-08 13:27:28178#if defined(OS_WIN)
[email protected]614e9fa2008-08-11 22:52:59179 // On Windows we use the same path as the exe.
180 wchar_t module_name[MAX_PATH];
181 GetModuleFileName(NULL, module_name, MAX_PATH);
182 log_file_name = new std::wstring(module_name);
183 std::wstring::size_type last_backslash =
184 log_file_name->rfind('\\', log_file_name->size());
185 if (last_backslash != std::wstring::npos)
186 log_file_name->erase(last_backslash + 1);
187 *log_file_name += L"debug.log";
188#elif defined(OS_POSIX)
189 // On other platforms we just use the current directory.
190 log_file_name = new std::string("debug.log");
191#endif
initial.commitd7cae122008-07-26 21:49:38192 }
193
[email protected]1d8c2702008-08-19 23:39:32194 if (logging_destination == LOG_ONLY_TO_FILE ||
195 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
[email protected]614e9fa2008-08-11 22:52:59196#if defined(OS_WIN)
[email protected]1d8c2702008-08-19 23:39:32197 log_file = CreateFile(log_file_name->c_str(), GENERIC_WRITE,
initial.commitd7cae122008-07-26 21:49:38198 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
199 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
200 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
[email protected]1d8c2702008-08-19 23:39:32201 // try the current directory
202 log_file = CreateFile(L".\\debug.log", GENERIC_WRITE,
203 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
204 OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
205 if (log_file == INVALID_HANDLE_VALUE || log_file == NULL) {
206 log_file = NULL;
207 return false;
208 }
initial.commitd7cae122008-07-26 21:49:38209 }
[email protected]1d8c2702008-08-19 23:39:32210 SetFilePointer(log_file, 0, 0, FILE_END);
[email protected]78c6dd62009-06-08 23:29:11211#elif defined(OS_POSIX)
212 log_file = fopen(log_file_name->c_str(), "a");
213 if (log_file == NULL)
214 return false;
[email protected]f6abeba2008-08-08 13:27:28215#endif
[email protected]1d8c2702008-08-19 23:39:32216 }
217
initial.commitd7cae122008-07-26 21:49:38218 return true;
219}
220
[email protected]4883a4e2009-06-06 19:59:36221#if defined(OS_LINUX)
222int GetLoggingFileDescriptor() {
223 // No locking needed, since this is only called by the zygote server,
224 // which is single-threaded.
225 if (log_file)
226 return fileno(log_file);
227 return -1;
228}
229#endif
230
initial.commitd7cae122008-07-26 21:49:38231void InitLogMutex() {
[email protected]f6abeba2008-08-08 13:27:28232#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38233 if (!log_mutex) {
234 // \ is not a legal character in mutex names so we replace \ with /
[email protected]614e9fa2008-08-11 22:52:59235 std::wstring safe_name(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38236 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 }
[email protected]f6abeba2008-08-08 13:27:28241#elif defined(OS_POSIX)
242 // statically initialized
243#endif
initial.commitd7cae122008-07-26 21:49:38244}
245
[email protected]f6abeba2008-08-08 13:27:28246void InitLogging(const PathChar* new_log_file, LoggingDestination logging_dest,
initial.commitd7cae122008-07-26 21:49:38247 LogLockingState lock_log, OldFileDeletionState delete_old) {
[email protected]bb975362009-01-21 01:00:22248 g_enable_dcheck =
249 CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableDCHECK);
initial.commitd7cae122008-07-26 21:49:38250
251 if (log_file) {
252 // calling InitLogging twice or after some log call has already opened the
253 // default log file will re-initialize to the new options
[email protected]f6abeba2008-08-08 13:27:28254 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38255 log_file = NULL;
256 }
257
258 lock_log_file = lock_log;
259 logging_destination = logging_dest;
260
261 // ignore file options if logging is disabled or only to system
262 if (logging_destination == LOG_NONE ||
263 logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG)
264 return;
265
[email protected]614e9fa2008-08-11 22:52:59266 if (!log_file_name)
267 log_file_name = new PathString();
268 *log_file_name = new_log_file;
initial.commitd7cae122008-07-26 21:49:38269 if (delete_old == DELETE_OLD_LOG_FILE)
[email protected]614e9fa2008-08-11 22:52:59270 DeleteFilePath(*log_file_name);
initial.commitd7cae122008-07-26 21:49:38271
272 if (lock_log_file == LOCK_LOG_FILE) {
273 InitLogMutex();
274 } else if (!log_lock) {
275 log_lock = new LockImpl();
276 }
277
278 InitializeLogFileHandle();
279}
280
281void SetMinLogLevel(int level) {
282 min_log_level = level;
283}
284
285int GetMinLogLevel() {
286 return min_log_level;
287}
288
289void SetLogFilterPrefix(const char* filter) {
290 if (log_filter_prefix) {
[email protected]614e9fa2008-08-11 22:52:59291 delete log_filter_prefix;
initial.commitd7cae122008-07-26 21:49:38292 log_filter_prefix = NULL;
293 }
294
[email protected]614e9fa2008-08-11 22:52:59295 if (filter)
296 log_filter_prefix = new std::string(filter);
initial.commitd7cae122008-07-26 21:49:38297}
298
299void SetLogItems(bool enable_process_id, bool enable_thread_id,
300 bool enable_timestamp, bool enable_tickcount) {
301 log_process_id = enable_process_id;
302 log_thread_id = enable_thread_id;
303 log_timestamp = enable_timestamp;
304 log_tickcount = enable_tickcount;
305}
306
307void SetLogAssertHandler(LogAssertHandlerFunction handler) {
308 log_assert_handler = handler;
309}
310
[email protected]fb62a532009-02-12 01:19:05311void SetLogReportHandler(LogReportHandlerFunction handler) {
312 log_report_handler = handler;
313}
314
initial.commitd7cae122008-07-26 21:49:38315// Displays a message box to the user with the error message in it. For
316// Windows programs, it's possible that the message loop is messed up on
317// a fatal error, and creating a MessageBox will cause that message loop
318// to be run. Instead, we try to spawn another process that displays its
319// command line. We look for "Debug Message.exe" in the same directory as
320// the application. If it exists, we use it, otherwise, we use a regular
321// message box.
322void DisplayDebugMessage(const std::string& str) {
323 if (str.empty())
324 return;
325
[email protected]f6abeba2008-08-08 13:27:28326#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38327 // look for the debug dialog program next to our application
328 wchar_t prog_name[MAX_PATH];
329 GetModuleFileNameW(NULL, prog_name, MAX_PATH);
330 wchar_t* backslash = wcsrchr(prog_name, '\\');
331 if (backslash)
332 backslash[1] = 0;
333 wcscat_s(prog_name, MAX_PATH, L"debug_message.exe");
334
[email protected]047a03f2009-10-07 02:10:20335 std::wstring cmdline = UTF8ToWide(str);
[email protected]3ca4214c12009-03-25 22:12:02336 if (cmdline.empty())
337 return;
initial.commitd7cae122008-07-26 21:49:38338
339 STARTUPINFO startup_info;
340 memset(&startup_info, 0, sizeof(startup_info));
341 startup_info.cb = sizeof(startup_info);
342
343 PROCESS_INFORMATION process_info;
[email protected]3ca4214c12009-03-25 22:12:02344 if (CreateProcessW(prog_name, &cmdline[0], NULL, NULL, false, 0, NULL,
initial.commitd7cae122008-07-26 21:49:38345 NULL, &startup_info, &process_info)) {
346 WaitForSingleObject(process_info.hProcess, INFINITE);
347 CloseHandle(process_info.hThread);
348 CloseHandle(process_info.hProcess);
349 } else {
350 // debug process broken, let's just do a message box
[email protected]3ca4214c12009-03-25 22:12:02351 MessageBoxW(NULL, &cmdline[0], L"Fatal error",
initial.commitd7cae122008-07-26 21:49:38352 MB_OK | MB_ICONHAND | MB_TOPMOST);
353 }
[email protected]f6abeba2008-08-08 13:27:28354#else
355 fprintf(stderr, "%s\n", str.c_str());
356#endif
initial.commitd7cae122008-07-26 21:49:38357}
358
[email protected]3f85caa2009-04-14 16:52:11359#if defined(OS_WIN)
360LogMessage::SaveLastError::SaveLastError() : last_error_(::GetLastError()) {
361}
362
363LogMessage::SaveLastError::~SaveLastError() {
364 ::SetLastError(last_error_);
365}
366#endif // defined(OS_WIN)
367
initial.commitd7cae122008-07-26 21:49:38368LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
369 int ctr)
370 : severity_(severity) {
371 Init(file, line);
372}
373
374LogMessage::LogMessage(const char* file, int line, const CheckOpString& result)
375 : severity_(LOG_FATAL) {
376 Init(file, line);
377 stream_ << "Check failed: " << (*result.str_);
378}
379
[email protected]fb62a532009-02-12 01:19:05380LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
381 const CheckOpString& result)
382 : severity_(severity) {
383 Init(file, line);
384 stream_ << "Check failed: " << (*result.str_);
385}
386
initial.commitd7cae122008-07-26 21:49:38387LogMessage::LogMessage(const char* file, int line)
388 : severity_(LOG_INFO) {
389 Init(file, line);
390}
391
392LogMessage::LogMessage(const char* file, int line, LogSeverity severity)
393 : severity_(severity) {
394 Init(file, line);
395}
396
397// writes the common header info to the stream
398void LogMessage::Init(const char* file, int line) {
399 // log only the filename
400 const char* last_slash = strrchr(file, '\\');
401 if (last_slash)
402 file = last_slash + 1;
403
404 // TODO(darin): It might be nice if the columns were fixed width.
405
406 stream_ << '[';
407 if (log_process_id)
[email protected]f8588472008-11-05 23:17:24408 stream_ << CurrentProcessId() << ':';
initial.commitd7cae122008-07-26 21:49:38409 if (log_thread_id)
[email protected]f8588472008-11-05 23:17:24410 stream_ << CurrentThreadId() << ':';
initial.commitd7cae122008-07-26 21:49:38411 if (log_timestamp) {
[email protected]defcd8f32009-05-13 00:03:43412 time_t t = time(NULL);
initial.commitd7cae122008-07-26 21:49:38413 struct tm local_time = {0};
[email protected]defcd8f32009-05-13 00:03:43414#if _MSC_VER >= 1400
initial.commitd7cae122008-07-26 21:49:38415 localtime_s(&local_time, &t);
initial.commitd7cae122008-07-26 21:49:38416#else
[email protected]defcd8f32009-05-13 00:03:43417 localtime_r(&t, &local_time);
initial.commitd7cae122008-07-26 21:49:38418#endif
[email protected]defcd8f32009-05-13 00:03:43419 struct tm* tm_time = &local_time;
initial.commitd7cae122008-07-26 21:49:38420 stream_ << std::setfill('0')
421 << std::setw(2) << 1 + tm_time->tm_mon
422 << std::setw(2) << tm_time->tm_mday
423 << '/'
424 << std::setw(2) << tm_time->tm_hour
425 << std::setw(2) << tm_time->tm_min
426 << std::setw(2) << tm_time->tm_sec
427 << ':';
428 }
429 if (log_tickcount)
[email protected]f8588472008-11-05 23:17:24430 stream_ << TickCount() << ':';
[email protected]52a261f2009-03-03 15:01:12431 stream_ << log_severity_names[severity_] << ":" << file <<
432 "(" << line << ")] ";
initial.commitd7cae122008-07-26 21:49:38433
434 message_start_ = stream_.tellp();
435}
436
437LogMessage::~LogMessage() {
438 // TODO(brettw) modify the macros so that nothing is executed when the log
439 // level is too high.
440 if (severity_ < min_log_level)
441 return;
442
443 std::string str_newline(stream_.str());
[email protected]1d8c2702008-08-19 23:39:32444#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38445 str_newline.append("\r\n");
[email protected]1d8c2702008-08-19 23:39:32446#else
447 str_newline.append("\n");
448#endif
initial.commitd7cae122008-07-26 21:49:38449
450 if (log_filter_prefix && severity_ <= kMaxFilteredLogLevel &&
[email protected]614e9fa2008-08-11 22:52:59451 str_newline.compare(message_start_, log_filter_prefix->size(),
452 log_filter_prefix->data()) != 0) {
initial.commitd7cae122008-07-26 21:49:38453 return;
454 }
455
456 if (logging_destination == LOG_ONLY_TO_SYSTEM_DEBUG_LOG ||
[email protected]f6abeba2008-08-08 13:27:28457 logging_destination == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
458#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38459 OutputDebugStringA(str_newline.c_str());
[email protected]107bc0f12008-08-26 17:48:18460 if (severity_ >= kAlwaysPrintErrorLevel)
461#endif
[email protected]31ae0352008-08-25 23:28:37462 // TODO(erikkay): this interferes with the layout tests since it grabs
463 // stderr and stdout and diffs them against known data. Our info and warn
464 // logs add noise to that. Ideally, the layout tests would set the log
465 // level to ignore anything below error. When that happens, we should
466 // take this fprintf out of the #else so that Windows users can benefit
467 // from the output when running tests from the command-line. In the
468 // meantime, we leave this in for Mac and Linux, but until this is fixed
469 // they won't be able to pass any layout tests that have info or warn logs.
470 // See http://b/1343647
[email protected]a33c9892008-08-25 20:10:31471 fprintf(stderr, "%s", str_newline.c_str());
472 } else if (severity_ >= kAlwaysPrintErrorLevel) {
473 // When we're only outputting to a log file, above a certain log level, we
474 // should still output to stderr so that we can better detect and diagnose
475 // problems with unit tests, especially on the buildbots.
476 fprintf(stderr, "%s", str_newline.c_str());
[email protected]f6abeba2008-08-08 13:27:28477 }
[email protected]52a261f2009-03-03 15:01:12478
initial.commitd7cae122008-07-26 21:49:38479 // write to log file
480 if (logging_destination != LOG_NONE &&
481 logging_destination != LOG_ONLY_TO_SYSTEM_DEBUG_LOG &&
482 InitializeLogFileHandle()) {
[email protected]52a261f2009-03-03 15:01:12483 // We can have multiple threads and/or processes, so try to prevent them
484 // from clobbering each other's writes.
initial.commitd7cae122008-07-26 21:49:38485 if (lock_log_file == LOCK_LOG_FILE) {
486 // Ensure that the mutex is initialized in case the client app did not
[email protected]52a261f2009-03-03 15:01:12487 // call InitLogging. This is not thread safe. See below.
initial.commitd7cae122008-07-26 21:49:38488 InitLogMutex();
489
[email protected]f6abeba2008-08-08 13:27:28490#if defined(OS_WIN)
[email protected]c0e27152009-08-03 18:35:53491 ::WaitForSingleObject(log_mutex, INFINITE);
492 // WaitForSingleObject could have returned WAIT_ABANDONED. We don't
493 // abort the process here. UI tests might be crashy sometimes,
494 // and aborting the test binary only makes the problem worse.
495 // We also don't use LOG macros because that might lead to an infinite
496 // loop. For more info see http://crbug.com/18028.
[email protected]f6abeba2008-08-08 13:27:28497#elif defined(OS_POSIX)
498 pthread_mutex_lock(&log_mutex);
499#endif
initial.commitd7cae122008-07-26 21:49:38500 } else {
501 // use the lock
502 if (!log_lock) {
503 // The client app did not call InitLogging, and so the lock has not
504 // been created. We do this on demand, but if two threads try to do
505 // this at the same time, there will be a race condition to create
506 // the lock. This is why InitLogging should be called from the main
507 // thread at the beginning of execution.
508 log_lock = new LockImpl();
509 }
510 log_lock->Lock();
511 }
512
[email protected]f6abeba2008-08-08 13:27:28513#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38514 SetFilePointer(log_file, 0, 0, SEEK_END);
515 DWORD num_written;
[email protected]52a261f2009-03-03 15:01:12516 WriteFile(log_file,
[email protected]5982f1f32009-03-03 15:10:58517 static_cast<const void*>(str_newline.c_str()),
[email protected]52a261f2009-03-03 15:01:12518 static_cast<DWORD>(str_newline.length()),
519 &num_written,
520 NULL);
[email protected]f6abeba2008-08-08 13:27:28521#else
522 fprintf(log_file, "%s", str_newline.c_str());
523#endif
initial.commitd7cae122008-07-26 21:49:38524
525 if (lock_log_file == LOCK_LOG_FILE) {
[email protected]f6abeba2008-08-08 13:27:28526#if defined(OS_WIN)
initial.commitd7cae122008-07-26 21:49:38527 ReleaseMutex(log_mutex);
[email protected]f6abeba2008-08-08 13:27:28528#elif defined(OS_POSIX)
529 pthread_mutex_unlock(&log_mutex);
530#endif
initial.commitd7cae122008-07-26 21:49:38531 } else {
532 log_lock->Unlock();
533 }
534 }
535
536 if (severity_ == LOG_FATAL) {
537 // display a message or break into the debugger on a fatal error
[email protected]1ffe08c12008-08-13 11:15:11538 if (DebugUtil::BeingDebugged()) {
539 DebugUtil::BreakDebugger();
540 } else {
[email protected]96fd0032009-04-24 00:13:08541#ifndef NDEBUG
542 // Dump a stack trace on a fatal.
543 StackTrace trace;
544 stream_ << "\n"; // Newline to separate from log message.
545 trace.OutputToStream(&stream_);
546#endif
547
initial.commitd7cae122008-07-26 21:49:38548 if (log_assert_handler) {
549 // make a copy of the string for the handler out of paranoia
550 log_assert_handler(std::string(stream_.str()));
551 } else {
[email protected]4d5901272008-11-06 00:33:50552 // Don't use the string with the newline, get a fresh version to send to
553 // the debug message process. We also don't display assertions to the
554 // user in release mode. The enduser can't do anything with this
555 // information, and displaying message boxes when the application is
556 // hosed can cause additional problems.
557#ifndef NDEBUG
initial.commitd7cae122008-07-26 21:49:38558 DisplayDebugMessage(stream_.str());
[email protected]4d5901272008-11-06 00:33:50559#endif
initial.commitd7cae122008-07-26 21:49:38560 // Crash the process to generate a dump.
[email protected]1ffe08c12008-08-13 11:15:11561 DebugUtil::BreakDebugger();
initial.commitd7cae122008-07-26 21:49:38562 }
563 }
[email protected]fb62a532009-02-12 01:19:05564 } else if (severity_ == LOG_ERROR_REPORT) {
565 // We are here only if the user runs with --enable-dcheck in release mode.
566 if (log_report_handler) {
567 log_report_handler(std::string(stream_.str()));
568 } else {
569 DisplayDebugMessage(stream_.str());
570 }
initial.commitd7cae122008-07-26 21:49:38571 }
572}
573
[email protected]d8617a62009-10-09 23:52:20574#if defined(OS_WIN)
575// This has already been defined in the header, but defining it again as DWORD
576// ensures that the type used in the header is equivalent to DWORD. If not,
577// the redefinition is a compile error.
578typedef DWORD SystemErrorCode;
579#endif
580
581SystemErrorCode GetLastSystemErrorCode() {
582#if defined(OS_WIN)
583 return ::GetLastError();
584#elif defined(OS_POSIX)
585 return errno;
586#else
587#error Not implemented
588#endif
589}
590
591#if defined(OS_WIN)
592Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
593 int line,
594 LogSeverity severity,
595 SystemErrorCode err,
596 const char* module)
597 : err_(err),
598 module_(module),
599 log_message_(file, line, severity) {
600}
601
602Win32ErrorLogMessage::Win32ErrorLogMessage(const char* file,
603 int line,
604 LogSeverity severity,
605 SystemErrorCode err)
606 : err_(err),
607 module_(NULL),
608 log_message_(file, line, severity) {
609}
610
611Win32ErrorLogMessage::~Win32ErrorLogMessage() {
612 const int error_message_buffer_size = 256;
613 char msgbuf[error_message_buffer_size];
614 DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM;
615 HMODULE hmod;
616 if (module_) {
617 hmod = GetModuleHandleA(module_);
618 if (hmod) {
619 flags |= FORMAT_MESSAGE_FROM_HMODULE;
620 } else {
621 // This makes a nested Win32ErrorLogMessage. It will have module_ of NULL
622 // so it will not call GetModuleHandle, so recursive errors are
623 // impossible.
624 DPLOG(WARNING) << "Couldn't open module " << module_
625 << " for error message query";
626 }
627 } else {
628 hmod = NULL;
629 }
630 DWORD len = FormatMessageA(flags,
631 hmod,
632 err_,
633 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
634 msgbuf,
635 sizeof(msgbuf) / sizeof(msgbuf[0]),
636 NULL);
637 if (len) {
638 while ((len > 0) &&
639 isspace(static_cast<unsigned char>(msgbuf[len - 1]))) {
640 msgbuf[--len] = 0;
641 }
642 stream() << ": " << msgbuf;
643 } else {
644 stream() << ": Error " << GetLastError() << " while retrieving error "
645 << err_;
646 }
647}
648#elif defined(OS_POSIX)
649ErrnoLogMessage::ErrnoLogMessage(const char* file,
650 int line,
651 LogSeverity severity,
652 SystemErrorCode err)
653 : err_(err),
654 log_message_(file, line, severity) {
655}
656
657ErrnoLogMessage::~ErrnoLogMessage() {
658 stream() << ": " << safe_strerror(err_);
659}
660#endif // OS_WIN
661
initial.commitd7cae122008-07-26 21:49:38662void CloseLogFile() {
663 if (!log_file)
664 return;
665
[email protected]f6abeba2008-08-08 13:27:28666 CloseFile(log_file);
initial.commitd7cae122008-07-26 21:49:38667 log_file = NULL;
668}
669
[email protected]96fd0032009-04-24 00:13:08670} // namespace logging
initial.commitd7cae122008-07-26 21:49:38671
672std::ostream& operator<<(std::ostream& out, const wchar_t* wstr) {
[email protected]047a03f2009-10-07 02:10:20673 return out << WideToUTF8(std::wstring(wstr));
initial.commitd7cae122008-07-26 21:49:38674}