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

Unified 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 side-by-side diff with in-line comments
Download patch
« 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 »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/test/logging/win/file_logger.cc
diff --git a/chrome/test/logging/win/file_logger.cc b/chrome/test/logging/win/file_logger.cc
new file mode 100644
index 0000000000000000000000000000000000000000..3afdb60f9d965b8060185b560faa84ea9342552b
--- /dev/null
+++ b/chrome/test/logging/win/file_logger.cc
@@ -0,0 +1,258 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/test/logging/win/file_logger.h"
+
+#include <windows.h>
+#include <guiddef.h>
+#include <objbase.h>
+
+#include <ios>
+
+#include "base/debug/trace_event_win.h"
+#include "base/logging.h"
+#include "base/file_path.h"
+#include "base/logging_win.h"
+#include "base/string16.h"
+#include "base/utf_string_conversions.h"
+#include "base/win/event_trace_consumer.h"
+#include "base/win/registry.h"
+#include "chrome/common/env_vars.h"
+
+namespace logging_win {
+
+namespace {
+
+const wchar_t kChromeTestSession[] = L"chrome_tests";
+
+// From chrome_tab.cc: {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
+const GUID kChromeFrameProvider =
+ { 0x562bfc3, 0x2550, 0x45b4,
+ { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
+
+// From chrome/common/logging_chrome.cc: {7FE69228-633E-4f06-80C1-527FEA23E3A7}
+const GUID kChromeTraceProviderName =
+ { 0x7fe69228, 0x633e, 0x4f06,
+ { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
+
+// {81729947-CD2A-49e6-8885-785429F339F5}
+const GUID kChromeTestsProvider =
+ { 0x81729947, 0xcd2a, 0x49e6,
+ { 0x88, 0x85, 0x78, 0x54, 0x29, 0xf3, 0x39, 0xf5 } };
+
+// The configurations for the supported providers. This must be in sync with
+// FileLogger::EventProviderBits.
+const struct {
+ const GUID* provider_name;
+ uint8 level;
+ uint32 flags;
+} kProviders[] = {
+ { &kChromeTraceProviderName, 255, 0 },
+ { &kChromeFrameProvider, 255, 0 },
+ { &kChromeTestsProvider, 255, 0 },
+ { &base::debug::kChromeTraceProviderName, 255, 0 }
+};
+
+COMPILE_ASSERT((1 << arraysize(kProviders)) - 1 ==
+ FileLogger::kAllEventProviders,
+ size_of_kProviders_is_inconsistent_with_kAllEventProviders);
+
+// The provider bits that require CHROME_ETW_LOGGING in the environment.
+const uint32 kChromeLogProviders =
+ FileLogger::CHROME_LOG_PROVIDER | FileLogger::CHROME_FRAME_LOG_PROVIDER;
+const HKEY kEnvironmentRoot = HKEY_LOCAL_MACHINE;
+const wchar_t kEnvironmentKey[] =
+ L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
+const wchar_t kEnvironment[] = L"Environment";
+const unsigned int kBroadcastTimeoutMilliseconds = 2 * 1000;
+
+} // namespace
+
+// FileLogger::ScopedSystemEnvironmentVariable implementation.
+
+FileLogger::ScopedSystemEnvironmentVariable::ScopedSystemEnvironmentVariable(
+ const string16& variable,
+ const string16& value) {
+
+ // Set the value in this process and its children.
+ ::SetEnvironmentVariable(variable.c_str(), value.c_str());
+
+ // Set the value for the whole system and ask everyone to refresh.
+ base::win::RegKey environment;
+ LONG result = environment.Open(kEnvironmentRoot, kEnvironmentKey,
+ KEY_QUERY_VALUE | KEY_SET_VALUE);
+ if (result == ERROR_SUCCESS) {
+ string16 old_value;
+ // The actual value of the variable is insignificant in the eyes of Chrome.
+ if (environment.ReadValue(variable.c_str(),
+ &old_value) != ERROR_SUCCESS &&
+ environment.WriteValue(variable.c_str(),
+ value.c_str()) == ERROR_SUCCESS) {
+ environment.Close();
+ // Remember that this needs to be reversed in the dtor.
+ variable_ = variable;
+ NotifyOtherProcesses();
+ }
+ } else {
+ SetLastError(result);
+ PLOG(ERROR) << "Failed to open HKLM to check/modify the system environment";
+ }
+}
+
+FileLogger::ScopedSystemEnvironmentVariable::~ScopedSystemEnvironmentVariable()
+{
+ if (!variable_.empty()) {
+ base::win::RegKey environment;
+ if (environment.Open(kEnvironmentRoot, kEnvironmentKey,
+ KEY_SET_VALUE) == ERROR_SUCCESS) {
+ environment.DeleteValue(variable_.c_str());
+ environment.Close();
+ NotifyOtherProcesses();
+ }
+ }
+}
+
+// static
+void FileLogger::ScopedSystemEnvironmentVariable::NotifyOtherProcesses() {
+ // Announce to the system that a change has been made so that the shell and
+ // other Windowsy bits pick it up; see
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682653.aspx.
+ SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
+ reinterpret_cast<LPARAM>(kEnvironment), SMTO_ABORTIFHUNG,
+ kBroadcastTimeoutMilliseconds, NULL);
+}
+
+bool FileLogger::is_initialized_ = false;
+
+FileLogger::FileLogger()
+ : event_provider_mask_() {
+}
+
+FileLogger::~FileLogger() {
+ if (is_logging()) {
+ LOG(ERROR)
+ << __FUNCTION__ << " don't forget to call FileLogger::StopLogging()";
+ StopLogging();
+ }
+
+ is_initialized_ = false;
+}
+
+// Returns false if all providers could not be enabled. A log message is
+// produced for each provider that could not be enabled.
+bool FileLogger::EnableProviders() {
+ // Default to false if there's at least one provider.
+ bool result = (event_provider_mask_ == 0);
+
+ // Generate ETW log events for this test binary. Log messages at and above
+ // logging::GetMinLogLevel() will continue to go to stderr as well. This
+ // leads to double logging in case of test failures: each LOG statement at
+ // or above the min level will go to stderr during test execution, and then
+ // all events logged to the file session will be dumped again. If this
+ // turns out to be an issue, one could call logging::SetMinLogLevel(INT_MAX)
+ // here (stashing away the previous min log level to be restored in
+ // DisableProviders) to suppress stderr logging during test execution. Then
+ // those events in the file that were logged at/above the old min level from
+ // the test binary could be dumped to stderr if there were no failures.
+ if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
+ logging::LogEventProvider::Initialize(kChromeTestsProvider);
+
+ HRESULT hr = S_OK;
+ for (size_t i = 0; i < arraysize(kProviders); ++i) {
+ if (event_provider_mask_ & (1 << i)) {
+ hr = controller_.EnableProvider(*kProviders[i].provider_name,
+ kProviders[i].level,
+ kProviders[i].flags);
+ if (FAILED(hr)) {
+ LOG(ERROR) << "Failed to enable event provider " << i
+ << "; hr=" << std::hex << hr;
+ } else {
+ result = true;
+ }
+ }
+ }
+
+ return result;
+}
+
+void FileLogger::DisableProviders() {
+ HRESULT hr = S_OK;
+ for (size_t i = 0; i < arraysize(kProviders); ++i) {
+ if (event_provider_mask_ & (1 << i)) {
+ hr = controller_.DisableProvider(*kProviders[i].provider_name);
+ LOG_IF(ERROR, FAILED(hr)) << "Failed to disable event provider "
+ << i << "; hr=" << std::hex << hr;
+ }
+ }
+
+ if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
+ logging::LogEventProvider::Uninitialize();
+}
+
+void FileLogger::Initialize() {
+ Initialize(kAllEventProviders);
+}
+
+void FileLogger::Initialize(uint32 event_provider_mask) {
+ CHECK(!is_initialized_);
+
+ // Set up CHROME_ETW_LOGGING in the environment if providers that require it
+ // are enabled.
+ if (event_provider_mask & kChromeLogProviders) {
+ etw_logging_configurator_.reset(new ScopedSystemEnvironmentVariable(
+ ASCIIToWide(env_vars::kEtwLogging), L"1"));
+ }
+
+ // Stop a previous session that wasn't shut down properly.
+ base::win::EtwTraceProperties ignore;
+ HRESULT hr = base::win::EtwTraceController::Stop(kChromeTestSession,
+ &ignore);
+ LOG_IF(ERROR, FAILED(hr) &&
+ hr != HRESULT_FROM_WIN32(ERROR_WMI_INSTANCE_NOT_FOUND))
+ << "Failed to stop a previous trace session; hr=" << std::hex << hr;
+
+ event_provider_mask_ = event_provider_mask;
+
+ is_initialized_ = true;
+}
+
+bool FileLogger::StartLogging(const FilePath& log_file) {
+ HRESULT hr =
+ controller_.StartFileSession(kChromeTestSession,
+ log_file.value().c_str(), false);
+ if (SUCCEEDED(hr)) {
+ // Ignore the return value here in the hopes that at least one provider was
+ // enabled.
+ if (!EnableProviders()) {
+ LOG(ERROR) << "Failed to enable any provider.";
+ controller_.Stop(NULL);
+ return false;
+ }
+ } else {
+ if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
+ LOG(WARNING) << "Access denied while trying to start trace session. "
+ "This is expected when not running as an administrator.";
+ } else {
+ LOG(ERROR) << "Failed to start trace session to file " << log_file.value()
+ << "; hr=" << std::hex << hr;
+ }
+ return false;
+ }
+ return true;
+}
+
+void FileLogger::StopLogging() {
+ HRESULT hr = S_OK;
+
+ DisableProviders();
+
+ hr = controller_.Flush(NULL);
+ LOG_IF(ERROR, FAILED(hr))
+ << "Failed to flush events; hr=" << std::hex << hr;
+ hr = controller_.Stop(NULL);
+ LOG_IF(ERROR, FAILED(hr))
+ << "Failed to stop ETW session; hr=" << std::hex << hr;
+}
+
+} // namespace logging_win
« 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