|  | // Copyright (c) 2011 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 "base/logging_win.h" | 
|  | #include "base/memory/singleton.h" | 
|  | #include <initguid.h>  // NOLINT | 
|  |  | 
|  | namespace logging { | 
|  |  | 
|  | using base::win::EtwEventLevel; | 
|  | using base::win::EtwMofEvent; | 
|  |  | 
|  | DEFINE_GUID(kLogEventId, | 
|  | 0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7); | 
|  |  | 
|  | LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) { | 
|  | } | 
|  |  | 
|  | LogEventProvider* LogEventProvider::GetInstance() { | 
|  | return base::Singleton<LogEventProvider, base::StaticMemorySingletonTraits< | 
|  | LogEventProvider>>::get(); | 
|  | } | 
|  |  | 
|  | bool LogEventProvider::LogMessage(logging::LogSeverity severity, | 
|  | const char* file, int line, size_t message_start, | 
|  | const std::string& message) { | 
|  | EtwEventLevel level = TRACE_LEVEL_NONE; | 
|  |  | 
|  | // Convert the log severity to the most appropriate ETW trace level. | 
|  | if (severity >= 0) { | 
|  | switch (severity) { | 
|  | case LOG_INFO: | 
|  | level = TRACE_LEVEL_INFORMATION; | 
|  | break; | 
|  | case LOG_WARNING: | 
|  | level = TRACE_LEVEL_WARNING; | 
|  | break; | 
|  | case LOG_ERROR: | 
|  | level = TRACE_LEVEL_ERROR; | 
|  | break; | 
|  | case LOG_FATAL: | 
|  | level = TRACE_LEVEL_FATAL; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Bail if we're not logging, not at that level, | 
|  | // or if we're post-atexit handling. | 
|  | LogEventProvider* provider = LogEventProvider::GetInstance(); | 
|  | if (provider == NULL || level > provider->enable_level()) | 
|  | return false; | 
|  |  | 
|  | // And now log the event. | 
|  | if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) { | 
|  | EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level); | 
|  | event.SetField(0, message.length() + 1 - message_start, | 
|  | message.c_str() + message_start); | 
|  |  | 
|  | provider->Log(event.get()); | 
|  | } else { | 
|  | const size_t kMaxBacktraceDepth = 32; | 
|  | void* backtrace[kMaxBacktraceDepth]; | 
|  | DWORD depth = 0; | 
|  |  | 
|  | // Capture a stack trace if one is requested. | 
|  | // requested per our enable flags. | 
|  | if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE) | 
|  | depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL); | 
|  |  | 
|  | EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level); | 
|  | if (file == NULL) | 
|  | file = ""; | 
|  |  | 
|  | // Add the stack trace. | 
|  | event.SetField(0, sizeof(depth), &depth); | 
|  | event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace); | 
|  | // The line. | 
|  | event.SetField(2, sizeof(line), &line); | 
|  | // The file. | 
|  | event.SetField(3, strlen(file) + 1, file); | 
|  | // And finally the message. | 
|  | event.SetField(4, message.length() + 1 - message_start, | 
|  | message.c_str() + message_start); | 
|  |  | 
|  | provider->Log(event.get()); | 
|  | } | 
|  |  | 
|  | // Don't increase verbosity in other log destinations. | 
|  | if (severity < provider->old_log_level_) | 
|  | return true; | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void LogEventProvider::Initialize(const GUID& provider_name) { | 
|  | LogEventProvider* provider = LogEventProvider::GetInstance(); | 
|  |  | 
|  | provider->set_provider_name(provider_name); | 
|  | provider->Register(); | 
|  |  | 
|  | // Register our message handler with logging. | 
|  | SetLogMessageHandler(LogMessage); | 
|  | } | 
|  |  | 
|  | void LogEventProvider::Uninitialize() { | 
|  | LogEventProvider::GetInstance()->Unregister(); | 
|  | } | 
|  |  | 
|  | void LogEventProvider::OnEventsEnabled() { | 
|  | // Grab the old log level so we can restore it later. | 
|  | old_log_level_ = GetMinLogLevel(); | 
|  |  | 
|  | // Convert the new trace level to a logging severity | 
|  | // and enable logging at that level. | 
|  | EtwEventLevel level = enable_level(); | 
|  | if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) { | 
|  | SetMinLogLevel(LOG_FATAL); | 
|  | } else if (level == TRACE_LEVEL_ERROR) { | 
|  | SetMinLogLevel(LOG_ERROR); | 
|  | } else if (level == TRACE_LEVEL_WARNING) { | 
|  | SetMinLogLevel(LOG_WARNING); | 
|  | } else if (level == TRACE_LEVEL_INFORMATION) { | 
|  | SetMinLogLevel(LOG_INFO); | 
|  | } else if (level >= TRACE_LEVEL_VERBOSE) { | 
|  | // Above INFO, we enable verbose levels with negative severities. | 
|  | SetMinLogLevel(TRACE_LEVEL_INFORMATION - level); | 
|  | } | 
|  | } | 
|  |  | 
|  | void LogEventProvider::OnEventsDisabled() { | 
|  | // Restore the old log level. | 
|  | SetMinLogLevel(old_log_level_); | 
|  | } | 
|  |  | 
|  | }  // namespace logging |