blob: a5f168a068d4a53e8a3ec6dcd6f5b3aef4f02dc1 [file] [log] [blame]
[email protected]4a100992011-06-14 18:22:461// Copyright (c) 2011 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.commit09911bf2008-07-26 23:55:294
[email protected]ec657802008-11-07 20:05:395#include "build/build_config.h"
6
[email protected]d55aaa132009-09-28 21:08:047// Need to include this before most other files because it defines
8// IPC_MESSAGE_LOG_ENABLED. We need to use it to define
9// IPC_MESSAGE_MACROS_LOG_ENABLED so render_messages.h will generate the
10// ViewMsgLog et al. functions.
11#include "ipc/ipc_message.h"
12
13// On Windows, the about:ipc dialog shows IPCs; on POSIX, we hook up a
14// logger in this file. (We implement about:ipc on Mac but implement
15// the loggers here anyway). We need to do this real early to be sure
16// IPC_MESSAGE_MACROS_LOG_ENABLED doesn't get undefined.
17#if defined(OS_POSIX) && defined(IPC_MESSAGE_LOG_ENABLED)
18#define IPC_MESSAGE_MACROS_LOG_ENABLED
[email protected]d55aaa132009-09-28 21:08:0419#include "chrome/common/render_messages.h"
[email protected]bf7cc5382011-05-27 08:26:0620#include "content/common/devtools_messages.h"
[email protected]105303e2011-03-14 22:16:1021#include "content/common/plugin_messages.h"
[email protected]4d223d32011-03-12 06:38:5622#include "content/common/worker_messages.h"
[email protected]d55aaa132009-09-28 21:08:0423#endif
24
[email protected]ec657802008-11-07 20:05:3925#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:2926#include <windows.h>
[email protected]ec657802008-11-07 20:05:3927#endif
initial.commit09911bf2008-07-26 23:55:2928
initial.commit09911bf2008-07-26 23:55:2929#include <fstream>
30
31#include "chrome/common/logging_chrome.h"
32
33#include "base/command_line.h"
[email protected]0eb9f4342008-11-21 18:48:5234#include "base/compiler_specific.h"
[email protected]58580352010-10-26 04:07:5035#include "base/debug/debugger.h"
[email protected]76b90d312010-08-03 03:00:5036#include "base/environment.h"
[email protected]73e23482009-08-13 00:26:5837#include "base/file_path.h"
initial.commit09911bf2008-07-26 23:55:2938#include "base/file_util.h"
39#include "base/logging.h"
40#include "base/path_service.h"
[email protected]528c56d2010-07-30 19:28:4441#include "base/string_number_conversions.h"
[email protected]5d91c9e2010-07-28 17:25:2842#include "base/string_util.h"
[email protected]61f93212011-01-24 14:37:0843#include "base/threading/thread_restrictions.h"
[email protected]77ee1b12010-06-14 16:21:3044#include "base/time.h"
[email protected]4197e092010-03-10 00:35:0545#include "base/utf_string_conversions.h"
[email protected]ab7ee5b2011-03-01 22:24:1446#include "chrome/common/chrome_constants.h"
initial.commit09911bf2008-07-26 23:55:2947#include "chrome/common/chrome_paths.h"
48#include "chrome/common/chrome_switches.h"
initial.commit09911bf2008-07-26 23:55:2949#include "chrome/common/env_vars.h"
[email protected]51d5e162009-07-27 19:23:5450#include "ipc/ipc_logging.h"
[email protected]ab7ee5b2011-03-01 22:24:1451
[email protected]2b07b8412009-11-25 15:26:3452#if defined(OS_WIN)
53#include "base/logging_win.h"
54#include <initguid.h>
55#endif
initial.commit09911bf2008-07-26 23:55:2956
[email protected]ab7ee5b2011-03-01 22:24:1457namespace {
58
initial.commit09911bf2008-07-26 23:55:2959// When true, this means that error dialogs should not be shown.
[email protected]ab7ee5b2011-03-01 22:24:1460bool dialogs_are_suppressed_ = false;
initial.commit09911bf2008-07-26 23:55:2961
62// This should be true for exactly the period between the end of
63// InitChromeLogging() and the beginning of CleanupChromeLogging().
[email protected]ab7ee5b2011-03-01 22:24:1464bool chrome_logging_initialized_ = false;
initial.commit09911bf2008-07-26 23:55:2965
[email protected]7109dc32011-02-02 22:58:2966// Set if we caled InitChromeLogging() but failed to initialize.
[email protected]ab7ee5b2011-03-01 22:24:1467bool chrome_logging_failed_ = false;
[email protected]7109dc32011-02-02 22:58:2968
[email protected]30f547c2010-08-04 01:00:0169// This should be true for exactly the period between the end of
70// InitChromeLogging() and the beginning of CleanupChromeLogging().
[email protected]ab7ee5b2011-03-01 22:24:1471bool chrome_logging_redirected_ = false;
[email protected]30f547c2010-08-04 01:00:0172
[email protected]2b07b8412009-11-25 15:26:3473#if defined(OS_WIN)
74// {7FE69228-633E-4f06-80C1-527FEA23E3A7}
[email protected]ab7ee5b2011-03-01 22:24:1475const GUID kChromeTraceProviderName = {
[email protected]162ac0f2010-11-04 15:50:4976 0x7fe69228, 0x633e, 0x4f06,
77 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
[email protected]2b07b8412009-11-25 15:26:3478#endif
79
initial.commit09911bf2008-07-26 23:55:2980// Assertion handler for logging errors that occur when dialogs are
81// silenced. To record a new error, pass the log string associated
82// with that error in the str parameter.
[email protected]0eb9f4342008-11-21 18:48:5283MSVC_DISABLE_OPTIMIZE();
[email protected]ab7ee5b2011-03-01 22:24:1484void SilentRuntimeAssertHandler(const std::string& str) {
[email protected]58580352010-10-26 04:07:5085 base::debug::BreakDebugger();
initial.commit09911bf2008-07-26 23:55:2986}
[email protected]ab7ee5b2011-03-01 22:24:1487void SilentRuntimeReportHandler(const std::string& str) {
[email protected]6cc67d7f2009-02-12 06:48:2488}
[email protected]ab7ee5b2011-03-01 22:24:1489#if defined(OS_WIN)
90// Handler to silently dump the current process when there is an assert in
91// chrome.
92void DumpProcessAssertHandler(const std::string& str) {
93 // Get the breakpad pointer from chrome.exe
94 typedef void (__cdecl *DumpProcessFunction)();
95 DumpProcessFunction DumpProcess = reinterpret_cast<DumpProcessFunction>(
96 ::GetProcAddress(::GetModuleHandle(chrome::kBrowserProcessExecutableName),
97 "DumpProcess"));
98 if (DumpProcess)
99 DumpProcess();
100}
101#endif // OS_WIN
[email protected]0eb9f4342008-11-21 18:48:52102MSVC_ENABLE_OPTIMIZE();
initial.commit09911bf2008-07-26 23:55:29103
104// Suppresses error/assertion dialogs and enables the logging of
105// those errors into silenced_errors_.
[email protected]ab7ee5b2011-03-01 22:24:14106void SuppressDialogs() {
initial.commit09911bf2008-07-26 23:55:29107 if (dialogs_are_suppressed_)
108 return;
109
110 logging::SetLogAssertHandler(SilentRuntimeAssertHandler);
[email protected]6cc67d7f2009-02-12 06:48:24111 logging::SetLogReportHandler(SilentRuntimeReportHandler);
initial.commit09911bf2008-07-26 23:55:29112
[email protected]ec657802008-11-07 20:05:39113#if defined(OS_WIN)
initial.commit09911bf2008-07-26 23:55:29114 UINT new_flags = SEM_FAILCRITICALERRORS |
115 SEM_NOGPFAULTERRORBOX |
116 SEM_NOOPENFILEERRORBOX;
117
118 // Preserve existing error mode, as discussed at http://t/dmea
119 UINT existing_flags = SetErrorMode(new_flags);
120 SetErrorMode(existing_flags | new_flags);
[email protected]ec657802008-11-07 20:05:39121#endif
initial.commit09911bf2008-07-26 23:55:29122
123 dialogs_are_suppressed_ = true;
124}
125
[email protected]ab7ee5b2011-03-01 22:24:14126} // anonymous namespace
127
initial.commit09911bf2008-07-26 23:55:29128namespace logging {
129
[email protected]77ee1b12010-06-14 16:21:30130LoggingDestination DetermineLogMode(const CommandLine& command_line) {
initial.commit09911bf2008-07-26 23:55:29131 // only use OutputDebugString in debug mode
132#ifdef NDEBUG
133 bool enable_logging = false;
[email protected]b7e0a2a2009-10-13 02:07:25134 const char *kInvertLoggingSwitch = switches::kEnableLogging;
initial.commit09911bf2008-07-26 23:55:29135 const logging::LoggingDestination kDefaultLoggingMode =
136 logging::LOG_ONLY_TO_FILE;
137#else
138 bool enable_logging = true;
[email protected]b7e0a2a2009-10-13 02:07:25139 const char *kInvertLoggingSwitch = switches::kDisableLogging;
initial.commit09911bf2008-07-26 23:55:29140 const logging::LoggingDestination kDefaultLoggingMode =
141 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG;
142#endif
143
144 if (command_line.HasSwitch(kInvertLoggingSwitch))
145 enable_logging = !enable_logging;
146
147 logging::LoggingDestination log_mode;
148 if (enable_logging) {
[email protected]3bba9582009-08-05 01:29:12149 // Let --enable-logging=stderr force only stderr, particularly useful for
150 // non-debug builds where otherwise you can't get logs to stderr at all.
[email protected]c4e52f0d2009-11-06 19:55:16151 if (command_line.GetSwitchValueASCII(switches::kEnableLogging) == "stderr")
[email protected]3bba9582009-08-05 01:29:12152 log_mode = logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG;
153 else
154 log_mode = kDefaultLoggingMode;
initial.commit09911bf2008-07-26 23:55:29155 } else {
156 log_mode = logging::LOG_NONE;
157 }
[email protected]77ee1b12010-06-14 16:21:30158 return log_mode;
159}
initial.commit09911bf2008-07-26 23:55:29160
[email protected]77ee1b12010-06-14 16:21:30161#if defined(OS_CHROMEOS)
[email protected]c7d5da992010-10-28 00:20:21162namespace {
163FilePath GenerateTimestampedName(const FilePath& base_path,
164 base::Time timestamp) {
[email protected]77ee1b12010-06-14 16:21:30165 base::Time::Exploded time_deets;
166 timestamp.LocalExplode(&time_deets);
[email protected]93f10522010-10-31 16:27:48167 std::string suffix = base::StringPrintf("_%02d%02d%02d-%02d%02d%02d",
168 time_deets.year,
169 time_deets.month,
170 time_deets.day_of_month,
171 time_deets.hour,
172 time_deets.minute,
173 time_deets.second);
[email protected]c7d5da992010-10-28 00:20:21174 return base_path.InsertBeforeExtension(suffix);
[email protected]77ee1b12010-06-14 16:21:30175}
176
[email protected]c7d5da992010-10-28 00:20:21177FilePath SetUpSymlinkIfNeeded(const FilePath& symlink_path, bool new_log) {
[email protected]f25b33a2010-10-28 20:15:51178 DCHECK(!symlink_path.empty());
179
[email protected]c7d5da992010-10-28 00:20:21180 // If not starting a new log, then just log through the existing
181 // symlink, but if the symlink doesn't exist, create it. If
182 // starting a new log, then delete the old symlink and make a new
183 // one to a fresh log file.
184 FilePath target_path;
[email protected]0750b1442010-11-02 21:59:37185 bool symlink_exists = file_util::PathExists(symlink_path);
186 if (new_log || !symlink_exists) {
[email protected]c7d5da992010-10-28 00:20:21187 target_path = GenerateTimestampedName(symlink_path, base::Time::Now());
188
189 // We don't care if the unlink fails; we're going to continue anyway.
[email protected]723571a2010-12-03 17:37:54190 if (::unlink(symlink_path.value().c_str()) == -1) {
[email protected]0750b1442010-11-02 21:59:37191 if (symlink_exists) // only warn if we might expect it to succeed.
[email protected]c7d5da992010-10-28 00:20:21192 PLOG(WARNING) << "Unable to unlink " << symlink_path.value();
193 }
[email protected]723571a2010-12-03 17:37:54194 if (!file_util::CreateSymbolicLink(target_path, symlink_path)) {
[email protected]c7d5da992010-10-28 00:20:21195 PLOG(ERROR) << "Unable to create symlink " << symlink_path.value()
196 << " pointing at " << target_path.value();
197 }
198 } else {
[email protected]723571a2010-12-03 17:37:54199 if (!file_util::ReadSymbolicLink(symlink_path, &target_path))
[email protected]c7d5da992010-10-28 00:20:21200 PLOG(ERROR) << "Unable to read symlink " << symlink_path.value();
[email protected]c7d5da992010-10-28 00:20:21201 }
202 return target_path;
203}
204
205void RemoveSymlinkAndLog(const FilePath& link_path,
206 const FilePath& target_path) {
207 if (::unlink(link_path.value().c_str()) == -1)
208 PLOG(WARNING) << "Unable to unlink symlink " << link_path.value();
209 if (::unlink(target_path.value().c_str()) == -1)
210 PLOG(WARNING) << "Unable to unlink log file " << target_path.value();
211}
212
213} // anonymous namespace
214
[email protected]0750b1442010-11-02 21:59:37215FilePath GetSessionLogFile(const CommandLine& command_line) {
216 FilePath log_dir;
217 std::string log_dir_str;
218 scoped_ptr<base::Environment> env(base::Environment::Create());
219 if (env->GetVar(env_vars::kSessionLogDir, &log_dir_str) &&
220 !log_dir_str.empty()) {
221 log_dir = FilePath(log_dir_str);
222 } else {
223 PathService::Get(chrome::DIR_USER_DATA, &log_dir);
224 FilePath login_profile =
225 command_line.GetSwitchValuePath(switches::kLoginProfile);
226 log_dir = log_dir.Append(login_profile);
227 }
228 return log_dir.Append(GetLogFileName().BaseName());
229}
230
231void RedirectChromeLogging(const CommandLine& command_line) {
[email protected]30f547c2010-08-04 01:00:01232 DCHECK(!chrome_logging_redirected_) <<
233 "Attempted to redirect logging when it was already initialized.";
[email protected]0750b1442010-11-02 21:59:37234
235 // Redirect logs to the session log directory, if set. Otherwise
236 // defaults to the profile dir.
237 FilePath log_path = GetSessionLogFile(command_line);
[email protected]c7d5da992010-10-28 00:20:21238
[email protected]61f93212011-01-24 14:37:08239 // Creating symlink causes us to do blocking IO on UI thread.
240 // Temporarily allow it until we fix http://crbug.com/61143
241 base::ThreadRestrictions::ScopedAllowIO allow_io;
[email protected]c7d5da992010-10-28 00:20:21242 // Always force a new symlink when redirecting.
243 FilePath target_path = SetUpSymlinkIfNeeded(log_path, true);
244
[email protected]7c10f7552011-01-11 01:03:36245 logging::DcheckState dcheck_state =
246 command_line.HasSwitch(switches::kEnableDCHECK) ?
247 logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS :
248 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
249
[email protected]c7d5da992010-10-28 00:20:21250 // ChromeOS always logs through the symlink, so it shouldn't be
251 // deleted if it already exists.
252 if (!InitLogging(log_path.value().c_str(),
253 DetermineLogMode(command_line),
254 logging::LOCK_LOG_FILE,
[email protected]7c10f7552011-01-11 01:03:36255 logging::APPEND_TO_OLD_LOG_FILE,
256 dcheck_state)) {
[email protected]c7d5da992010-10-28 00:20:21257 LOG(ERROR) << "Unable to initialize logging to " << log_path.value();
258 RemoveSymlinkAndLog(log_path, target_path);
259 } else {
260 chrome_logging_redirected_ = true;
261 }
[email protected]77ee1b12010-06-14 16:21:30262}
[email protected]0750b1442010-11-02 21:59:37263
[email protected]85271192011-05-10 20:38:25264#endif // OS_CHROMEOS
[email protected]77ee1b12010-06-14 16:21:30265
266void InitChromeLogging(const CommandLine& command_line,
267 OldFileDeletionState delete_old_log_file) {
268 DCHECK(!chrome_logging_initialized_) <<
269 "Attempted to initialize logging when it was already initialized.";
270
271#if defined(OS_POSIX) && defined(IPC_MESSAGE_LOG_ENABLED)
[email protected]21fa3a12010-12-08 23:34:16272 IPC::Logging::set_log_function_map(&g_log_function_mapping);
[email protected]77ee1b12010-06-14 16:21:30273#endif
[email protected]4a100992011-06-14 18:22:46274 LoggingDestination logging_dest = DetermineLogMode(command_line);
275 FilePath log_path;
276#if defined(OS_CHROMEOS)
277 FilePath target_path;
278#endif
[email protected]77ee1b12010-06-14 16:21:30279
[email protected]4a100992011-06-14 18:22:46280 // Don't resolve the log path unless we need to. Otherwise we leave an open
281 // ALPC handle after sandbox lockdown on Windows.
282 if (logging_dest == LOG_ONLY_TO_FILE ||
283 logging_dest == LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG) {
284 log_path = GetLogFileName();
[email protected]c7d5da992010-10-28 00:20:21285
[email protected]77ee1b12010-06-14 16:21:30286#if defined(OS_CHROMEOS)
[email protected]4a100992011-06-14 18:22:46287 // For BWSI (Incognito) logins, we want to put the logs in the user
288 // profile directory that is created for the temporary session instead
289 // of in the system log directory, for privacy reasons.
290 if (command_line.HasSwitch(switches::kGuestSession))
291 log_path = GetSessionLogFile(command_line);
[email protected]0750b1442010-11-02 21:59:37292
[email protected]4a100992011-06-14 18:22:46293 // On ChromeOS we log to the symlink. We force creation of a new
294 // symlink if we've been asked to delete the old log, since that
295 // indicates the start of a new session.
296 target_path = SetUpSymlinkIfNeeded(
297 log_path, delete_old_log_file == logging::DELETE_OLD_LOG_FILE);
[email protected]c7d5da992010-10-28 00:20:21298
[email protected]4a100992011-06-14 18:22:46299 // Because ChromeOS manages the move to a new session by redirecting
300 // the link, it shouldn't remove the old file in the logging code,
301 // since that will remove the newly created link instead.
302 delete_old_log_file = logging::APPEND_TO_OLD_LOG_FILE;
[email protected]77ee1b12010-06-14 16:21:30303#endif
[email protected]4a100992011-06-14 18:22:46304 }
[email protected]77ee1b12010-06-14 16:21:30305
[email protected]7c10f7552011-01-11 01:03:36306 logging::DcheckState dcheck_state =
307 command_line.HasSwitch(switches::kEnableDCHECK) ?
308 logging::ENABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS :
309 logging::DISABLE_DCHECK_FOR_NON_OFFICIAL_RELEASE_BUILDS;
310
[email protected]c7d5da992010-10-28 00:20:21311 bool success = InitLogging(log_path.value().c_str(),
[email protected]4a100992011-06-14 18:22:46312 logging_dest,
[email protected]c7d5da992010-10-28 00:20:21313 logging::LOCK_LOG_FILE,
[email protected]7c10f7552011-01-11 01:03:36314 delete_old_log_file,
315 dcheck_state);
[email protected]c7d5da992010-10-28 00:20:21316
317#if defined(OS_CHROMEOS)
318 if (!success) {
319 PLOG(ERROR) << "Unable to initialize logging to " << log_path.value()
320 << " (which should be a link to " << target_path.value() << ")";
321 RemoveSymlinkAndLog(log_path, target_path);
[email protected]7109dc32011-02-02 22:58:29322 chrome_logging_failed_ = true;
[email protected]c7d5da992010-10-28 00:20:21323 return;
324 }
325#else
326 if (!success) {
327 PLOG(ERROR) << "Unable to initialize logging to " << log_path.value();
[email protected]7109dc32011-02-02 22:58:29328 chrome_logging_failed_ = true;
[email protected]c7d5da992010-10-28 00:20:21329 return;
330 }
331#endif
initial.commit09911bf2008-07-26 23:55:29332
[email protected]81e0a852010-08-17 00:38:12333 // Default to showing error dialogs.
334 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoErrorDialogs))
335 logging::SetShowErrorDialogs(true);
336
initial.commit09911bf2008-07-26 23:55:29337 // we want process and thread IDs because we have a lot of things running
[email protected]c7d5da992010-10-28 00:20:21338 logging::SetLogItems(true, // enable_process_id
339 true, // enable_thread_id
340 false, // enable_timestamp
341 true); // enable_tickcount
initial.commit09911bf2008-07-26 23:55:29342
343 // We call running in unattended mode "headless", and allow
344 // headless mode to be configured either by the Environment
345 // Variable or by the Command Line Switch. This is for
346 // automated test purposes.
[email protected]76b90d312010-08-03 03:00:50347 scoped_ptr<base::Environment> env(base::Environment::Create());
[email protected]9432ade2010-08-04 23:43:20348 if (env->HasVar(env_vars::kHeadless) ||
initial.commit09911bf2008-07-26 23:55:29349 command_line.HasSwitch(switches::kNoErrorDialogs))
350 SuppressDialogs();
351
[email protected]3deeb6b32010-10-05 21:53:52352 // Use a minimum log level if the command line asks for one,
353 // otherwise leave it at the default level (INFO).
354 if (command_line.HasSwitch(switches::kLoggingLevel)) {
355 std::string log_level = command_line.GetSwitchValueASCII(
356 switches::kLoggingLevel);
357 int level = 0;
358 if (base::StringToInt(log_level, &level) &&
359 level >= 0 && level < LOG_NUM_SEVERITIES) {
[email protected]bb5185c52008-08-29 19:51:06360 logging::SetMinLogLevel(level);
[email protected]3deeb6b32010-10-05 21:53:52361 } else {
362 LOG(WARNING) << "Bad log level: " << log_level;
363 }
[email protected]bb5185c52008-08-29 19:51:06364 }
365
[email protected]2b07b8412009-11-25 15:26:34366#if defined(OS_WIN)
367 // Enable trace control and transport through event tracing for Windows.
[email protected]9432ade2010-08-04 23:43:20368 if (env->HasVar(env_vars::kEtwLogging))
[email protected]2b07b8412009-11-25 15:26:34369 logging::LogEventProvider::Initialize(kChromeTraceProviderName);
370#endif
371
[email protected]ab7ee5b2011-03-01 22:24:14372#ifdef NDEBUG
373 if (command_line.HasSwitch(switches::kSilentDumpOnDCHECK) &&
374 command_line.HasSwitch(switches::kEnableDCHECK)) {
375#if defined(OS_WIN)
376 logging::SetLogReportHandler(DumpProcessAssertHandler);
377#endif
378 }
379#endif // NDEBUG
380
initial.commit09911bf2008-07-26 23:55:29381 chrome_logging_initialized_ = true;
382}
383
384// This is a no-op, but we'll keep it around in case
385// we need to do more cleanup in the future.
386void CleanupChromeLogging() {
[email protected]7109dc32011-02-02 22:58:29387 if (chrome_logging_failed_)
388 return; // We failed to initiailize logging, no cleanup.
389
initial.commit09911bf2008-07-26 23:55:29390 DCHECK(chrome_logging_initialized_) <<
391 "Attempted to clean up logging when it wasn't initialized.";
392
393 CloseLogFile();
394
395 chrome_logging_initialized_ = false;
[email protected]30f547c2010-08-04 01:00:01396 chrome_logging_redirected_ = false;
initial.commit09911bf2008-07-26 23:55:29397}
398
[email protected]73e23482009-08-13 00:26:58399FilePath GetLogFileName() {
[email protected]c83dd912010-04-06 18:50:51400 std::string filename;
[email protected]76b90d312010-08-03 03:00:50401 scoped_ptr<base::Environment> env(base::Environment::Create());
[email protected]3ba7e082010-08-07 02:57:59402 if (env->GetVar(env_vars::kLogFileName, &filename) && !filename.empty()) {
[email protected]c83dd912010-04-06 18:50:51403#if defined(OS_WIN)
404 return FilePath(UTF8ToWide(filename).c_str());
405#elif defined(OS_POSIX)
406 return FilePath(filename.c_str());
407#endif
408 }
initial.commit09911bf2008-07-26 23:55:29409
[email protected]73e23482009-08-13 00:26:58410 const FilePath log_filename(FILE_PATH_LITERAL("chrome_debug.log"));
411 FilePath log_path;
initial.commit09911bf2008-07-26 23:55:29412
413 if (PathService::Get(chrome::DIR_LOGS, &log_path)) {
[email protected]73e23482009-08-13 00:26:58414 log_path = log_path.Append(log_filename);
initial.commit09911bf2008-07-26 23:55:29415 return log_path;
416 } else {
417 // error with path service, just use some default file somewhere
418 return log_filename;
419 }
420}
421
422bool DialogsAreSuppressed() {
423 return dialogs_are_suppressed_;
424}
425
426size_t GetFatalAssertions(AssertionList* assertions) {
427 // In this function, we don't assume that assertions is non-null, so
428 // that if you just want an assertion count, you can pass in NULL.
429 if (assertions)
430 assertions->clear();
431 size_t assertion_count = 0;
432
433 std::ifstream log_file;
[email protected]73e23482009-08-13 00:26:58434 log_file.open(GetLogFileName().value().c_str());
initial.commit09911bf2008-07-26 23:55:29435 if (!log_file.is_open())
436 return 0;
437
438 std::string utf8_line;
439 std::wstring wide_line;
[email protected]4a3dab22009-11-11 17:36:50440 while (!log_file.eof()) {
initial.commit09911bf2008-07-26 23:55:29441 getline(log_file, utf8_line);
442 if (utf8_line.find(":FATAL:") != std::string::npos) {
443 wide_line = UTF8ToWide(utf8_line);
444 if (assertions)
445 assertions->push_back(wide_line);
446 ++assertion_count;
447 }
448 }
449 log_file.close();
450
451 return assertion_count;
452}
453
[email protected]c83dd912010-04-06 18:50:51454} // namespace logging