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