Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(414)

Side by Side Diff: chrome/test/base/file_logger_win.cc

Issue 9584017: New test infrastructure for producing verbose logs in failing tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: tweaked comments Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 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.
4
5 #include "chrome/test/base/file_logger_win.h"
6
7 #include <windows.h>
8 #include <guiddef.h>
9 #include <objbase.h>
10
11 #include <ios>
12
13 #include "base/debug/trace_event_win.h"
14 #include "base/logging.h"
15 #include "base/file_path.h"
16 #include "base/logging_win.h"
17 #include "base/string16.h"
18 #include "base/utf_string_conversions.h"
19 #include "base/win/event_trace_consumer.h"
20 #include "base/win/registry.h"
21 #include "chrome/common/env_vars.h"
22
23 namespace {
24
25 bool g_is_initialized = false;
robertshield 2012/03/09 16:58:04 Consider making this a static member of FileLogger
grt (UTC plus 2) 2012/03/09 17:55:25 Done.
26
27 const wchar_t kChromeTestSession[] = L"chrome_tests";
28
29 // From chrome_tab.cc: {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
30 const GUID kChromeFrameProvider =
31 { 0x562bfc3, 0x2550, 0x45b4,
32 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
33
34 // From chrome/common/logging_chrome.cc: {7FE69228-633E-4f06-80C1-527FEA23E3A7}
35 const GUID kChromeTraceProviderName =
36 { 0x7fe69228, 0x633e, 0x4f06,
37 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
38
39 // {81729947-CD2A-49e6-8885-785429F339F5}
40 const GUID kChromeTestsProvider =
41 { 0x81729947, 0xcd2a, 0x49e6,
42 { 0x88, 0x85, 0x78, 0x54, 0x29, 0xf3, 0x39, 0xf5 } };
43
44 // The configurations for the supported providers. This must be in sync with
45 // FileLogger::EventProviderBits.
46 const struct {
47 const GUID* provider_name;
48 uint8 level;
49 uint32 flags;
50 } kProviders[] = {
51 { &kChromeTraceProviderName, 255, 0 },
52 { &kChromeFrameProvider, 255, 0 },
53 { &kChromeTestsProvider, 255, 0 },
54 { &base::debug::kChromeTraceProviderName, 255, 0 }
55 };
56
57 COMPILE_ASSERT((1 << arraysize(kProviders)) - 1 ==
58 FileLogger::kAllEventProviders,
59 size_of_kProviders_is_inconsistent_with_kAllEventProviders);
60
61 const HKEY kEnvironmentRoot = HKEY_LOCAL_MACHINE;
62 const wchar_t kEnvironmentKey[] =
63 L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
64 const wchar_t kEnvironment[] = L"Environment";
65 unsigned int kBroadcastTimeoutMilliseconds = 2 * 1000;
robertshield 2012/03/09 16:58:04 const?
grt (UTC plus 2) 2012/03/09 17:55:25 Done.
66
67 } // namespace
68
69 FileLogger::FileLogger()
70 : event_provider_mask_(),
71 added_chrome_etw_variable_() {
72 }
73
74 FileLogger::~FileLogger() {
75 if (event_provider_mask_) {
76 LOG(WARNING)
77 << __FUNCTION__ << " don't forget to call FileLogger::Uninitialize()";
78 Uninitialize();
79 }
80 }
81
82 void FileLogger::ConfigureChromeEtwLogging() {
83 const string16 chrome_etw_logging(ASCIIToWide(env_vars::kEtwLogging));
84
85 // Set the value in this process and its children.
86 ::SetEnvironmentVariable(chrome_etw_logging.c_str(), L"1");
87
88 // Set the value for the whole system and ask everyone to refresh.
89 base::win::RegKey environment;
90 LONG result = environment.Open(kEnvironmentRoot, kEnvironmentKey,
91 KEY_QUERY_VALUE | KEY_SET_VALUE);
92 if (result == ERROR_SUCCESS) {
93 string16 value;
94 // The actual value of the variable is insignificant in the eyes of Chrome.
95 if (environment.ReadValue(chrome_etw_logging.c_str(),
96 &value) != ERROR_SUCCESS &&
97 environment.WriteValue(chrome_etw_logging.c_str(),
98 L"1") == ERROR_SUCCESS) {
99 environment.Close();
100 added_chrome_etw_variable_ = true;
101 // Announce to the system that a change has been made so that the shell
102 // and other Windowsy bits pick it up; see
103 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682653.aspx.
104 SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
105 reinterpret_cast<LPARAM>(kEnvironment),
106 SMTO_ABORTIFHUNG,
107 kBroadcastTimeoutMilliseconds, NULL);
108 }
109 } else {
110 SetLastError(result);
111 PLOG(ERROR) << "Failed to open HKLM to check/modify the system environment";
112 }
113 }
114
115 void FileLogger::RevertChromeEtwLogging() {
116 if (added_chrome_etw_variable_) {
117 base::win::RegKey environment;
118 if (environment.Open(kEnvironmentRoot, kEnvironmentKey,
119 KEY_SET_VALUE) == ERROR_SUCCESS) {
120 environment.DeleteValue(ASCIIToWide(env_vars::kEtwLogging).c_str());
121 environment.Close();
122 SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
123 reinterpret_cast<LPARAM>(kEnvironment),
124 SMTO_ABORTIFHUNG,
125 kBroadcastTimeoutMilliseconds, NULL);
126 }
127 added_chrome_etw_variable_ = false;
128 }
129 }
130
131 bool FileLogger::EnableProviders() {
132 bool result = true;
133
134 // Generate ETW log events for this test binary. Log messages at and above
135 // logging::GetMinLogLevel() will continue to go to stderr as well. This
136 // leads to double logging in case of test failures: each LOG statement at
137 // or above the min level will go to stderr during test execution, and then
138 // all events logged to the file session will be dumped again. If this
139 // turns out to be an issue, one could call logging::SetMinLogLevel(INT_MAX)
140 // here (stashing away the previous min log level to be restored in
141 // Uninitialize) to suppress stderr logging during test execution. Then those
142 // events in the file that were logged at/above the old min level from the
143 // test binary could be dumped to stderr if there were no failures.
144 if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
145 logging::LogEventProvider::Initialize(kChromeTestsProvider);
146
147 HRESULT hr = S_OK;
148 for (size_t i = 0; i < arraysize(kProviders); ++i) {
149 if (event_provider_mask_ & (1 << i)) {
150 hr = controller_.EnableProvider(*kProviders[i].provider_name,
151 kProviders[i].level,
152 kProviders[i].flags);
153 if (FAILED(hr)) {
154 result = false;
155 LOG(ERROR) << "Failed to enable event provider " << i
156 << "; hr=" << std::hex << hr;
157 }
158 }
159 }
160
161 return result;
162 }
163
164 void FileLogger::DisableProviders() {
165 HRESULT hr = S_OK;
166 for (size_t i = 0; i < arraysize(kProviders); ++i) {
167 if (event_provider_mask_ & (1 << i)) {
168 hr = controller_.DisableProvider(*kProviders[i].provider_name);
169 LOG_IF(ERROR, FAILED(hr)) << "Failed to disable event provider "
170 << i << "; hr=" << std::hex << hr;
171 }
172 }
173
174 if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
175 logging::LogEventProvider::Uninitialize();
176 }
177
178 void FileLogger::Initialize() {
179 Initialize(kAllEventProviders);
180 }
181
182 void FileLogger::Initialize(uint32 event_provider_mask) {
183 DCHECK(event_provider_mask_ == 0 && !added_chrome_etw_variable_);
184 CHECK(!g_is_initialized);
185
186 ConfigureChromeEtwLogging();
187
188 // Stop a previous session that wasn't shut down properly.
189 base::win::EtwTraceProperties ignore;
190 HRESULT hr = base::win::EtwTraceController::Stop(kChromeTestSession,
191 &ignore);
192 LOG_IF(ERROR, FAILED(hr) &&
193 hr != HRESULT_FROM_WIN32(ERROR_WMI_INSTANCE_NOT_FOUND))
194 << "Failed to stop a previous trace session; hr=" << std::hex << hr;
195
196 event_provider_mask_ = event_provider_mask;
197
198 g_is_initialized = true;
199 }
200
201 void FileLogger::Uninitialize() {
202 if (is_logging()) {
203 LOG(ERROR)
204 << __FUNCTION__ << " don't forget to call FileLogger::StopLogging()";
205 StopLogging();
206 }
207
208 event_provider_mask_ = 0;
209
210 RevertChromeEtwLogging();
211
212 g_is_initialized = false;
213 }
214
215 bool FileLogger::StartLogging(const FilePath& log_file) {
216 HRESULT hr =
217 controller_.StartFileSession(kChromeTestSession,
218 log_file.value().c_str(), false);
219 if (SUCCEEDED(hr)) {
220 EnableProviders();
221 } else {
222 if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
223 LOG(WARNING) << "Access denied while trying to start trace session. "
224 "This is expected when not running as an administrator.";
225 } else {
226 LOG(ERROR) << "Failed to start trace session to file " << log_file.value()
227 << "; hr=" << std::hex << hr;
228 }
229 return false;
230 }
231 return true;
232 }
233
234 void FileLogger::StopLogging() {
235 HRESULT hr = S_OK;
236
237 DisableProviders();
238
239 hr = controller_.Flush(NULL);
240 LOG_IF(ERROR, FAILED(hr))
241 << "Failed to flush events; hr=" << std::hex << hr;
242 hr = controller_.Stop(NULL);
243 LOG_IF(ERROR, FAILED(hr))
244 << "Failed to stop ETW session; hr=" << std::hex << hr;
245 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698