| // Copyright (c) 2009 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/atomicops.h" |
| #include "base/singleton.h" |
| #include <initguid.h> // NOLINT |
| |
| namespace { |
| |
| struct LogEventProviderTraits { |
| // WARNING: User has to deal with get() returning NULL. |
| static logging::LogEventProvider* New() { |
| if (base::subtle::NoBarrier_AtomicExchange(&dead_, 1)) |
| return NULL; |
| logging::LogEventProvider* ptr = |
| reinterpret_cast<logging::LogEventProvider*>(buffer_); |
| // We are protected by a memory barrier. |
| new(ptr) logging::LogEventProvider(); |
| return ptr; |
| } |
| |
| static void Delete(logging::LogEventProvider* p) { |
| base::subtle::NoBarrier_Store(&dead_, 1); |
| MemoryBarrier(); |
| p->logging::LogEventProvider::~LogEventProvider(); |
| } |
| |
| static const bool kRegisterAtExit = true; |
| |
| private: |
| static const size_t kBufferSize = (sizeof(logging::LogEventProvider) + |
| sizeof(intptr_t) - 1) / sizeof(intptr_t); |
| static intptr_t buffer_[kBufferSize]; |
| |
| // Signal the object was already deleted, so it is not revived. |
| static base::subtle::Atomic32 dead_; |
| }; |
| |
| intptr_t LogEventProviderTraits::buffer_[kBufferSize]; |
| base::subtle::Atomic32 LogEventProviderTraits::dead_ = 0; |
| |
| Singleton<logging::LogEventProvider, LogEventProviderTraits> log_provider; |
| |
| } // namespace |
| |
| namespace logging { |
| |
| DEFINE_GUID(kLogEventId, |
| 0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7); |
| |
| LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) { |
| } |
| |
| bool LogEventProvider::LogMessage(int severity, const std::string& message) { |
| EtwEventLevel level = TRACE_LEVEL_NONE; |
| |
| // Convert the log severity to the most appropriate ETW trace level. |
| switch (severity) { |
| case LOG_INFO: |
| level = TRACE_LEVEL_INFORMATION; |
| break; |
| case LOG_WARNING: |
| level = TRACE_LEVEL_WARNING; |
| break; |
| case LOG_ERROR: |
| case LOG_ERROR_REPORT: |
| 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 = log_provider.get(); |
| if (provider == NULL || level > provider->enable_level()) |
| return false; |
| |
| // And now log the event, with stack trace if one is |
| // requested per our enable flags. |
| if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE) { |
| const size_t kMaxBacktraceDepth = 32; |
| void* backtrace[kMaxBacktraceDepth]; |
| DWORD depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL); |
| EtwMofEvent<3> event(kLogEventId, LOG_MESSAGE_WITH_STACKTRACE, level); |
| |
| event.SetField(0, sizeof(depth), &depth); |
| event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace); |
| event.SetField(2, message.length() + 1, message.c_str()); |
| |
| provider->Log(event.get()); |
| } else { |
| EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level); |
| event.SetField(0, message.length() + 1, message.c_str()); |
| 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 = log_provider.get(); |
| |
| provider->set_provider_name(provider_name); |
| provider->Register(); |
| |
| // Register our message handler with logging. |
| SetLogMessageHandler(LogMessage); |
| } |
| |
| void LogEventProvider::Uninitialize() { |
| log_provider.get()->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(); |
| switch (level) { |
| case TRACE_LEVEL_NONE: |
| case TRACE_LEVEL_FATAL: |
| SetMinLogLevel(LOG_FATAL); |
| break; |
| case TRACE_LEVEL_ERROR: |
| SetMinLogLevel(LOG_ERROR); |
| break; |
| case TRACE_LEVEL_WARNING: |
| SetMinLogLevel(LOG_WARNING); |
| break; |
| case TRACE_LEVEL_INFORMATION: |
| case TRACE_LEVEL_VERBOSE: |
| SetMinLogLevel(LOG_INFO); |
| break; |
| } |
| } |
| |
| void LogEventProvider::OnEventsDisabled() { |
| // Restore the old log level. |
| SetMinLogLevel(old_log_level_); |
| } |
| |
| } // namespace logging |