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

Side by Side Diff: chrome/test/logging/win/file_logger.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: moved logging_win to logging/win so regular filename_rules work 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
« no previous file with comments | « chrome/test/logging/win/file_logger.h ('k') | chrome/test/logging/win/log_file_printer.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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/logging/win/file_logger.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 logging_win {
24
25 namespace {
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 // The provider bits that require CHROME_ETW_LOGGING in the environment.
62 const uint32 kChromeLogProviders =
63 FileLogger::CHROME_LOG_PROVIDER | FileLogger::CHROME_FRAME_LOG_PROVIDER;
64 const HKEY kEnvironmentRoot = HKEY_LOCAL_MACHINE;
65 const wchar_t kEnvironmentKey[] =
66 L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
67 const wchar_t kEnvironment[] = L"Environment";
68 const unsigned int kBroadcastTimeoutMilliseconds = 2 * 1000;
69
70 } // namespace
71
72 // FileLogger::ScopedSystemEnvironmentVariable implementation.
73
74 FileLogger::ScopedSystemEnvironmentVariable::ScopedSystemEnvironmentVariable(
75 const string16& variable,
76 const string16& value) {
77
78 // Set the value in this process and its children.
79 ::SetEnvironmentVariable(variable.c_str(), value.c_str());
80
81 // Set the value for the whole system and ask everyone to refresh.
82 base::win::RegKey environment;
83 LONG result = environment.Open(kEnvironmentRoot, kEnvironmentKey,
84 KEY_QUERY_VALUE | KEY_SET_VALUE);
85 if (result == ERROR_SUCCESS) {
86 string16 old_value;
87 // The actual value of the variable is insignificant in the eyes of Chrome.
88 if (environment.ReadValue(variable.c_str(),
89 &old_value) != ERROR_SUCCESS &&
90 environment.WriteValue(variable.c_str(),
91 value.c_str()) == ERROR_SUCCESS) {
92 environment.Close();
93 // Remember that this needs to be reversed in the dtor.
94 variable_ = variable;
95 NotifyOtherProcesses();
96 }
97 } else {
98 SetLastError(result);
99 PLOG(ERROR) << "Failed to open HKLM to check/modify the system environment";
100 }
101 }
102
103 FileLogger::ScopedSystemEnvironmentVariable::~ScopedSystemEnvironmentVariable()
104 {
105 if (!variable_.empty()) {
106 base::win::RegKey environment;
107 if (environment.Open(kEnvironmentRoot, kEnvironmentKey,
108 KEY_SET_VALUE) == ERROR_SUCCESS) {
109 environment.DeleteValue(variable_.c_str());
110 environment.Close();
111 NotifyOtherProcesses();
112 }
113 }
114 }
115
116 // static
117 void FileLogger::ScopedSystemEnvironmentVariable::NotifyOtherProcesses() {
118 // Announce to the system that a change has been made so that the shell and
119 // other Windowsy bits pick it up; see
120 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682653.aspx.
121 SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
122 reinterpret_cast<LPARAM>(kEnvironment), SMTO_ABORTIFHUNG,
123 kBroadcastTimeoutMilliseconds, NULL);
124 }
125
126 bool FileLogger::is_initialized_ = false;
127
128 FileLogger::FileLogger()
129 : event_provider_mask_() {
130 }
131
132 FileLogger::~FileLogger() {
133 if (is_logging()) {
134 LOG(ERROR)
135 << __FUNCTION__ << " don't forget to call FileLogger::StopLogging()";
136 StopLogging();
137 }
138
139 is_initialized_ = false;
140 }
141
142 // Returns false if all providers could not be enabled. A log message is
143 // produced for each provider that could not be enabled.
144 bool FileLogger::EnableProviders() {
145 // Default to false if there's at least one provider.
146 bool result = (event_provider_mask_ == 0);
147
148 // Generate ETW log events for this test binary. Log messages at and above
149 // logging::GetMinLogLevel() will continue to go to stderr as well. This
150 // leads to double logging in case of test failures: each LOG statement at
151 // or above the min level will go to stderr during test execution, and then
152 // all events logged to the file session will be dumped again. If this
153 // turns out to be an issue, one could call logging::SetMinLogLevel(INT_MAX)
154 // here (stashing away the previous min log level to be restored in
155 // DisableProviders) to suppress stderr logging during test execution. Then
156 // those events in the file that were logged at/above the old min level from
157 // the test binary could be dumped to stderr if there were no failures.
158 if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
159 logging::LogEventProvider::Initialize(kChromeTestsProvider);
160
161 HRESULT hr = S_OK;
162 for (size_t i = 0; i < arraysize(kProviders); ++i) {
163 if (event_provider_mask_ & (1 << i)) {
164 hr = controller_.EnableProvider(*kProviders[i].provider_name,
165 kProviders[i].level,
166 kProviders[i].flags);
167 if (FAILED(hr)) {
168 LOG(ERROR) << "Failed to enable event provider " << i
169 << "; hr=" << std::hex << hr;
170 } else {
171 result = true;
172 }
173 }
174 }
175
176 return result;
177 }
178
179 void FileLogger::DisableProviders() {
180 HRESULT hr = S_OK;
181 for (size_t i = 0; i < arraysize(kProviders); ++i) {
182 if (event_provider_mask_ & (1 << i)) {
183 hr = controller_.DisableProvider(*kProviders[i].provider_name);
184 LOG_IF(ERROR, FAILED(hr)) << "Failed to disable event provider "
185 << i << "; hr=" << std::hex << hr;
186 }
187 }
188
189 if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
190 logging::LogEventProvider::Uninitialize();
191 }
192
193 void FileLogger::Initialize() {
194 Initialize(kAllEventProviders);
195 }
196
197 void FileLogger::Initialize(uint32 event_provider_mask) {
198 CHECK(!is_initialized_);
199
200 // Set up CHROME_ETW_LOGGING in the environment if providers that require it
201 // are enabled.
202 if (event_provider_mask & kChromeLogProviders) {
203 etw_logging_configurator_.reset(new ScopedSystemEnvironmentVariable(
204 ASCIIToWide(env_vars::kEtwLogging), L"1"));
205 }
206
207 // Stop a previous session that wasn't shut down properly.
208 base::win::EtwTraceProperties ignore;
209 HRESULT hr = base::win::EtwTraceController::Stop(kChromeTestSession,
210 &ignore);
211 LOG_IF(ERROR, FAILED(hr) &&
212 hr != HRESULT_FROM_WIN32(ERROR_WMI_INSTANCE_NOT_FOUND))
213 << "Failed to stop a previous trace session; hr=" << std::hex << hr;
214
215 event_provider_mask_ = event_provider_mask;
216
217 is_initialized_ = true;
218 }
219
220 bool FileLogger::StartLogging(const FilePath& log_file) {
221 HRESULT hr =
222 controller_.StartFileSession(kChromeTestSession,
223 log_file.value().c_str(), false);
224 if (SUCCEEDED(hr)) {
225 // Ignore the return value here in the hopes that at least one provider was
226 // enabled.
227 if (!EnableProviders()) {
228 LOG(ERROR) << "Failed to enable any provider.";
229 controller_.Stop(NULL);
230 return false;
231 }
232 } else {
233 if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
234 LOG(WARNING) << "Access denied while trying to start trace session. "
235 "This is expected when not running as an administrator.";
236 } else {
237 LOG(ERROR) << "Failed to start trace session to file " << log_file.value()
238 << "; hr=" << std::hex << hr;
239 }
240 return false;
241 }
242 return true;
243 }
244
245 void FileLogger::StopLogging() {
246 HRESULT hr = S_OK;
247
248 DisableProviders();
249
250 hr = controller_.Flush(NULL);
251 LOG_IF(ERROR, FAILED(hr))
252 << "Failed to flush events; hr=" << std::hex << hr;
253 hr = controller_.Stop(NULL);
254 LOG_IF(ERROR, FAILED(hr))
255 << "Failed to stop ETW session; hr=" << std::hex << hr;
256 }
257
258 } // namespace logging_win
OLDNEW
« no previous file with comments | « chrome/test/logging/win/file_logger.h ('k') | chrome/test/logging/win/log_file_printer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698