diff options
Diffstat (limited to 'base/logging_win.cc')
-rw-r--r-- | base/logging_win.cc | 152 |
1 files changed, 152 insertions, 0 deletions
diff --git a/base/logging_win.cc b/base/logging_win.cc new file mode 100644 index 0000000..b3702aa --- /dev/null +++ b/base/logging_win.cc @@ -0,0 +1,152 @@ +// 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 |