blob: 232e5007975a048176965841b5aca5a132ff8f0e [file] [log] [blame]
license.botbf09a502008-08-24 00:55:551// 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.commit09911bf2008-07-26 23:55:294
5#include <windows.h>
6
7#include <iostream>
8#include <fstream>
9
10#include "chrome/common/logging_chrome.h"
11
12#include "base/command_line.h"
13#include "base/file_util.h"
14#include "base/logging.h"
15#include "base/path_service.h"
16#include "base/string_util.h"
17#include "chrome/common/chrome_paths.h"
18#include "chrome/common/chrome_switches.h"
19#include "chrome/common/env_util.h"
20#include "chrome/common/env_vars.h"
21
22// When true, this means that error dialogs should not be shown.
23static bool dialogs_are_suppressed_ = false;
24
25// This should be true for exactly the period between the end of
26// InitChromeLogging() and the beginning of CleanupChromeLogging().
27static bool chrome_logging_initialized_ = false;
28
29// Assertion handler for logging errors that occur when dialogs are
30// silenced. To record a new error, pass the log string associated
31// with that error in the str parameter.
32#pragma optimize("", off)
33static void SilentRuntimeAssertHandler(const std::string& str) {
34 __debugbreak();
35}
36#pragma optimize("", on)
37
38// Suppresses error/assertion dialogs and enables the logging of
39// those errors into silenced_errors_.
40static void SuppressDialogs() {
41 if (dialogs_are_suppressed_)
42 return;
43
44 logging::SetLogAssertHandler(SilentRuntimeAssertHandler);
45
46 UINT new_flags = SEM_FAILCRITICALERRORS |
47 SEM_NOGPFAULTERRORBOX |
48 SEM_NOOPENFILEERRORBOX;
49
50 // Preserve existing error mode, as discussed at http://t/dmea
51 UINT existing_flags = SetErrorMode(new_flags);
52 SetErrorMode(existing_flags | new_flags);
53
54 dialogs_are_suppressed_ = true;
55}
56
57namespace logging {
58
59void InitChromeLogging(const CommandLine& command_line,
60 OldFileDeletionState delete_old_log_file) {
61 DCHECK(!chrome_logging_initialized_) <<
62 "Attempted to initialize logging when it was already initialized.";
63
64 // only use OutputDebugString in debug mode
65#ifdef NDEBUG
66 bool enable_logging = false;
67 const wchar_t *kInvertLoggingSwitch = switches::kEnableLogging;
68 const logging::LoggingDestination kDefaultLoggingMode =
69 logging::LOG_ONLY_TO_FILE;
70#else
71 bool enable_logging = true;
72 const wchar_t *kInvertLoggingSwitch = switches::kDisableLogging;
73 const logging::LoggingDestination kDefaultLoggingMode =
74 logging::LOG_TO_BOTH_FILE_AND_SYSTEM_DEBUG_LOG;
75#endif
76
77 if (command_line.HasSwitch(kInvertLoggingSwitch))
78 enable_logging = !enable_logging;
79
80 logging::LoggingDestination log_mode;
81 if (enable_logging) {
82 log_mode = kDefaultLoggingMode;
83 } else {
84 log_mode = logging::LOG_NONE;
85 }
86
87 logging::InitLogging(GetLogFileName().c_str(),
88 log_mode,
89 logging::LOCK_LOG_FILE,
90 delete_old_log_file);
91
92 // we want process and thread IDs because we have a lot of things running
93 logging::SetLogItems(true, true, false, true);
94
95 // We call running in unattended mode "headless", and allow
96 // headless mode to be configured either by the Environment
97 // Variable or by the Command Line Switch. This is for
98 // automated test purposes.
99 if (env_util::HasEnvironmentVariable(env_vars::kHeadless) ||
100 command_line.HasSwitch(switches::kNoErrorDialogs))
101 SuppressDialogs();
102
103 std::wstring log_filter_prefix =
104 command_line.GetSwitchValue(switches::kLogFilterPrefix);
105 logging::SetLogFilterPrefix(WideToUTF8(log_filter_prefix).c_str());
106
[email protected]bb5185c52008-08-29 19:51:06107 // Use a minimum log level if the command line has one, otherwise set the
108 // default to LOG_WARNING.
109 std::wstring log_level = command_line.GetSwitchValue(switches::kLoggingLevel);
110 int level = 0;
111 if (StringToInt(log_level, &level)) {
112 if ((level >= 0) && (level < LOG_NUM_SEVERITIES))
113 logging::SetMinLogLevel(level);
114 } else {
115 logging::SetMinLogLevel(LOG_WARNING);
116 }
117
initial.commit09911bf2008-07-26 23:55:29118 chrome_logging_initialized_ = true;
119}
120
121// This is a no-op, but we'll keep it around in case
122// we need to do more cleanup in the future.
123void CleanupChromeLogging() {
124 DCHECK(chrome_logging_initialized_) <<
125 "Attempted to clean up logging when it wasn't initialized.";
126
127 CloseLogFile();
128
129 chrome_logging_initialized_ = false;
130}
131
132std::wstring GetLogFileName() {
133 wchar_t filename[MAX_PATH];
134 unsigned status = GetEnvironmentVariable(env_vars::kLogFileName,
135 filename, MAX_PATH);
136 if (status && (status <= MAX_PATH))
137 return std::wstring(filename);
138
139 const std::wstring log_filename(L"chrome_debug.log");
140 std::wstring log_path;
141
142 if (PathService::Get(chrome::DIR_LOGS, &log_path)) {
143 file_util::AppendToPath(&log_path, log_filename);
144 return log_path;
145 } else {
146 // error with path service, just use some default file somewhere
147 return log_filename;
148 }
149}
150
151bool DialogsAreSuppressed() {
152 return dialogs_are_suppressed_;
153}
154
155size_t GetFatalAssertions(AssertionList* assertions) {
156 // In this function, we don't assume that assertions is non-null, so
157 // that if you just want an assertion count, you can pass in NULL.
158 if (assertions)
159 assertions->clear();
160 size_t assertion_count = 0;
161
162 std::ifstream log_file;
163 log_file.open(GetLogFileName().c_str());
164 if (!log_file.is_open())
165 return 0;
166
167 std::string utf8_line;
168 std::wstring wide_line;
169 while(!log_file.eof()) {
170 getline(log_file, utf8_line);
171 if (utf8_line.find(":FATAL:") != std::string::npos) {
172 wide_line = UTF8ToWide(utf8_line);
173 if (assertions)
174 assertions->push_back(wide_line);
175 ++assertion_count;
176 }
177 }
178 log_file.close();
179
180 return assertion_count;
181}
182
183} // namespace logging
license.botbf09a502008-08-24 00:55:55184