15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2011 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/singleton.h"
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <initguid.h>  // NOLINT
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace logging {
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::EtwEventLevel;
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using base::win::EtwMofEvent;
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)DEFINE_GUID(kLogEventId,
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    0x7fe69228, 0x633e, 0x4f06, 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7);
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LogEventProvider::LogEventProvider() : old_log_level_(LOG_NONE) {
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)LogEventProvider* LogEventProvider::GetInstance() {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return Singleton<LogEventProvider,
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   StaticMemorySingletonTraits<LogEventProvider> >::get();
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool LogEventProvider::LogMessage(logging::LogSeverity severity,
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const char* file, int line, size_t message_start,
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& message) {
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwEventLevel level = TRACE_LEVEL_NONE;
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert the log severity to the most appropriate ETW trace level.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (severity >= 0) {
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    switch (severity) {
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case LOG_INFO:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        level = TRACE_LEVEL_INFORMATION;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case LOG_WARNING:
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        level = TRACE_LEVEL_WARNING;
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case LOG_ERROR:
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        level = TRACE_LEVEL_ERROR;
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      case LOG_FATAL:
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        level = TRACE_LEVEL_FATAL;
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        break;
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {  // severity < 0 is VLOG verbosity levels.
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    level = TRACE_LEVEL_INFORMATION - severity;
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Bail if we're not logging, not at that level,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // or if we're post-atexit handling.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LogEventProvider* provider = LogEventProvider::GetInstance();
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (provider == NULL || level > provider->enable_level())
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // And now log the event.
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (provider->enable_flags() & ENABLE_LOG_MESSAGE_ONLY) {
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EtwMofEvent<1> event(kLogEventId, LOG_MESSAGE, level);
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event.SetField(0, message.length() + 1 - message_start,
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        message.c_str() + message_start);
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provider->Log(event.get());
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const size_t kMaxBacktraceDepth = 32;
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    void* backtrace[kMaxBacktraceDepth];
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DWORD depth = 0;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Capture a stack trace if one is requested.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // requested per our enable flags.
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (provider->enable_flags() & ENABLE_STACK_TRACE_CAPTURE)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      depth = CaptureStackBackTrace(2, kMaxBacktraceDepth, backtrace, NULL);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    EtwMofEvent<5> event(kLogEventId, LOG_MESSAGE_FULL, level);
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (file == NULL)
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      file = "";
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Add the stack trace.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event.SetField(0, sizeof(depth), &depth);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event.SetField(1, sizeof(backtrace[0]) * depth, &backtrace);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The line.
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event.SetField(2, sizeof(line), &line);
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // The file.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event.SetField(3, strlen(file) + 1, file);
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // And finally the message.
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    event.SetField(4, message.length() + 1 - message_start,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        message.c_str() + message_start);
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    provider->Log(event.get());
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Don't increase verbosity in other log destinations.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (severity < provider->old_log_level_)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogEventProvider::Initialize(const GUID& provider_name) {
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LogEventProvider* provider = LogEventProvider::GetInstance();
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->set_provider_name(provider_name);
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  provider->Register();
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Register our message handler with logging.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetLogMessageHandler(LogMessage);
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogEventProvider::Uninitialize() {
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  LogEventProvider::GetInstance()->Unregister();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogEventProvider::OnEventsEnabled() {
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Grab the old log level so we can restore it later.
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  old_log_level_ = GetMinLogLevel();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Convert the new trace level to a logging severity
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // and enable logging at that level.
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  EtwEventLevel level = enable_level();
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (level == TRACE_LEVEL_NONE || level == TRACE_LEVEL_FATAL) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetMinLogLevel(LOG_FATAL);
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (level == TRACE_LEVEL_ERROR) {
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetMinLogLevel(LOG_ERROR);
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (level == TRACE_LEVEL_WARNING) {
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetMinLogLevel(LOG_WARNING);
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (level == TRACE_LEVEL_INFORMATION) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetMinLogLevel(LOG_INFO);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (level >= TRACE_LEVEL_VERBOSE) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Above INFO, we enable verbose levels with negative severities.
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    SetMinLogLevel(TRACE_LEVEL_INFORMATION - level);
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void LogEventProvider::OnEventsDisabled() {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Restore the old log level.
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  SetMinLogLevel(old_log_level_);
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace logging
139