Home | History | Annotate | Download | only in win
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/test/logging/win/log_file_reader.h"
      6 
      7 #include "base/debug/trace_event_win.h"
      8 #include "base/files/file_path.h"
      9 #include "base/lazy_instance.h"
     10 #include "base/logging_win.h"
     11 #include "base/synchronization/lock.h"
     12 #include "base/win/event_trace_consumer.h"
     13 #include "chrome/test/logging/win/mof_data_parser.h"
     14 
     15 namespace logging_win {
     16 
     17 namespace {
     18 
     19 // TODO(grt) This reverses a mapping produced by base/logging_win.cc's
     20 // LogEventProvider::LogMessage.  LogEventProvider should expose a way to map an
     21 // event level back to a log severity.
     22 logging::LogSeverity EventLevelToSeverity(uint8 level) {
     23   switch (level) {
     24   case TRACE_LEVEL_NONE:
     25     NOTREACHED();
     26     return logging::LOG_ERROR;
     27   case TRACE_LEVEL_FATAL:
     28     return logging::LOG_FATAL;
     29   case TRACE_LEVEL_ERROR:
     30     return logging::LOG_ERROR;
     31   case TRACE_LEVEL_WARNING:
     32     return logging::LOG_WARNING;
     33   case TRACE_LEVEL_INFORMATION:
     34     return logging::LOG_INFO;
     35   default:
     36     // Trace levels above information correspond to negative severity levels,
     37     // which are used for VLOG verbosity levels.
     38     return TRACE_LEVEL_INFORMATION - level;
     39   }
     40 }
     41 
     42 // TODO(grt) This reverses a mapping produced by base/debug/trace_event_win.cc's
     43 // TraceEventETWProvider::TraceEvent.  TraceEventETWProvider should expose a way
     44 // to map an event type back to a trace type.
     45 char EventTypeToTraceType(uint8 event_type) {
     46   switch (event_type) {
     47     case base::debug::kTraceEventTypeBegin:
     48       return TRACE_EVENT_PHASE_BEGIN;
     49       break;
     50     case base::debug::kTraceEventTypeEnd:
     51       return TRACE_EVENT_PHASE_END;
     52       break;
     53     case base::debug::kTraceEventTypeInstant:
     54       return TRACE_EVENT_PHASE_INSTANT;
     55       break;
     56     default:
     57       NOTREACHED();
     58       return '\0';
     59       break;
     60   }
     61 }
     62 
     63 class LogFileReader {
     64  public:
     65   explicit LogFileReader(LogFileDelegate* delegate);
     66   ~LogFileReader();
     67 
     68   static void ReadFile(const base::FilePath& log_file,
     69                        LogFileDelegate* delegate);
     70 
     71  private:
     72   // An implementation of a trace consumer that delegates to a given (at
     73   // compile-time) event processing function.
     74   template<void (*ProcessEventFn)(EVENT_TRACE*)>
     75   class TraceConsumer
     76       : public base::win::EtwTraceConsumerBase<TraceConsumer<ProcessEventFn> > {
     77    public:
     78     TraceConsumer() { }
     79     static void ProcessEvent(EVENT_TRACE* event) { (*ProcessEventFn)(event); }
     80    private:
     81     DISALLOW_COPY_AND_ASSIGN(TraceConsumer);
     82   };
     83 
     84   // Delegates to DispatchEvent() of the current LogDumper instance.
     85   static void ProcessEvent(EVENT_TRACE* event);
     86 
     87   // Handlers for the supported event types.
     88   bool OnLogMessageEvent(const EVENT_TRACE* event);
     89   bool OnLogMessageFullEvent(const EVENT_TRACE* event);
     90   bool OnTraceEvent(const EVENT_TRACE* event);
     91   bool OnFileHeader(const EVENT_TRACE* event);
     92 
     93   // Parses an event and passes it along to the delegate for processing.
     94   void DispatchEvent(const EVENT_TRACE* event);
     95 
     96   // Reads the file using a trace consumer.  |ProcessEvent| will be invoked for
     97   // each event in the file.
     98   void Read(const base::FilePath& log_file);
     99 
    100   // Protects use of the class; only one instance may be live at a time.
    101   static base::LazyInstance<base::Lock>::Leaky reader_lock_;
    102 
    103   // The currently living instance.
    104   static LogFileReader* instance_;
    105 
    106   // The delegate to be notified of events.
    107   LogFileDelegate* delegate_;
    108 };
    109 
    110 // static
    111 base::LazyInstance<base::Lock>::Leaky LogFileReader::reader_lock_ =
    112     LAZY_INSTANCE_INITIALIZER;
    113 
    114 // static
    115 LogFileReader* LogFileReader::instance_ = NULL;
    116 
    117 LogFileReader::LogFileReader(LogFileDelegate* delegate)
    118     : delegate_(delegate) {
    119   DCHECK(instance_ == NULL);
    120   DCHECK(delegate != NULL);
    121   instance_ = this;
    122 }
    123 
    124 LogFileReader::~LogFileReader() {
    125   DCHECK_EQ(instance_, this);
    126   instance_ = NULL;
    127 }
    128 
    129 // static
    130 void LogFileReader::ProcessEvent(EVENT_TRACE* event) {
    131   if (instance_ != NULL)
    132     instance_->DispatchEvent(event);
    133 }
    134 
    135 bool LogFileReader::OnLogMessageEvent(const EVENT_TRACE* event) {
    136   base::StringPiece message;
    137   MofDataParser parser(event);
    138 
    139   // See LogEventProvider::LogMessage where ENABLE_LOG_MESSAGE_ONLY is set.
    140   if (parser.ReadString(&message) && parser.empty()) {
    141     delegate_->OnLogMessage(event,
    142                             EventLevelToSeverity(event->Header.Class.Level),
    143                             message);
    144     return true;
    145   }
    146   return false;
    147 }
    148 
    149 bool LogFileReader::OnLogMessageFullEvent(const EVENT_TRACE* event) {
    150   DWORD stack_depth = 0;
    151   const intptr_t* backtrace = NULL;
    152   int line = 0;
    153   base::StringPiece file;
    154   base::StringPiece message;
    155   MofDataParser parser(event);
    156 
    157   // See LogEventProvider::LogMessage where ENABLE_LOG_MESSAGE_ONLY is not set.
    158   if (parser.ReadDWORD(&stack_depth) &&
    159       parser.ReadPointerArray(stack_depth, &backtrace) &&
    160       parser.ReadInt(&line) &&
    161       parser.ReadString(&file) &&
    162       parser.ReadString(&message) &&
    163       parser.empty()) {
    164     delegate_->OnLogMessageFull(event,
    165         EventLevelToSeverity(event->Header.Class.Level), stack_depth, backtrace,
    166         line, file, message);
    167     return true;
    168   }
    169   return false;
    170 }
    171 
    172 bool LogFileReader::OnTraceEvent(const EVENT_TRACE* event) {
    173   MofDataParser parser(event);
    174   base::StringPiece name;
    175   intptr_t id = 0;
    176   base::StringPiece extra;
    177   DWORD stack_depth = 0;
    178   const intptr_t* backtrace = NULL;
    179 
    180   // See TraceEventETWProvider::TraceEvent.
    181   if (parser.ReadString(&name) &&
    182       parser.ReadPointer(&id) &&
    183       parser.ReadString(&extra) &&
    184       (parser.empty() ||
    185        parser.ReadDWORD(&stack_depth) &&
    186        parser.ReadPointerArray(stack_depth, &backtrace) &&
    187        parser.empty())) {
    188     delegate_->OnTraceEvent(event, name,
    189         EventTypeToTraceType(event->Header.Class.Type), id, extra, stack_depth,
    190         backtrace);
    191     return true;
    192   }
    193   return false;
    194 }
    195 
    196 bool LogFileReader::OnFileHeader(const EVENT_TRACE* event) {
    197   MofDataParser parser(event);
    198   const TRACE_LOGFILE_HEADER* header = NULL;
    199 
    200   if (parser.ReadStructure(&header)) {
    201     delegate_->OnFileHeader(event, header);
    202     return true;
    203   }
    204   return false;
    205 }
    206 
    207 void LogFileReader::DispatchEvent(const EVENT_TRACE* event) {
    208   bool parsed = true;
    209 
    210   if (IsEqualGUID(event->Header.Guid, logging::kLogEventId)) {
    211     if (event->Header.Class.Type == logging::LOG_MESSAGE)
    212       parsed = OnLogMessageEvent(event);
    213     else if (event->Header.Class.Type == logging::LOG_MESSAGE_FULL)
    214       parsed = OnLogMessageFullEvent(event);
    215   } else if (IsEqualGUID(event->Header.Guid, base::debug::kTraceEventClass32)) {
    216     parsed = OnTraceEvent(event);
    217   } else if (IsEqualGUID(event->Header.Guid, EventTraceGuid)) {
    218     parsed = OnFileHeader(event);
    219   } else {
    220     DCHECK(parsed);
    221     delegate_->OnUnknownEvent(event);
    222   }
    223   if (!parsed)
    224     delegate_->OnUnparsableEvent(event);
    225 }
    226 
    227 void LogFileReader::Read(const base::FilePath& log_file) {
    228   TraceConsumer<&ProcessEvent> consumer;
    229   HRESULT hr = S_OK;
    230 
    231   hr = consumer.OpenFileSession(log_file.value().c_str());
    232   if (FAILED(hr)) {
    233     LOG(ERROR) << "Failed to open session for log file " << log_file.value()
    234                << "; hr=" << std::hex << hr;
    235   } else {
    236     consumer.Consume();
    237     consumer.Close();
    238   }
    239 }
    240 
    241 // static
    242 void LogFileReader::ReadFile(const base::FilePath& log_file,
    243                              LogFileDelegate* delegate) {
    244   base::AutoLock lock(reader_lock_.Get());
    245 
    246   LogFileReader(delegate).Read(log_file);
    247 }
    248 
    249 }  // namespace
    250 
    251 LogFileDelegate::LogFileDelegate() {
    252 }
    253 
    254 LogFileDelegate::~LogFileDelegate() {
    255 }
    256 
    257 void ReadLogFile(const base::FilePath& log_file, LogFileDelegate* delegate) {
    258   DCHECK(delegate);
    259   LogFileReader::ReadFile(log_file, delegate);
    260 }
    261 
    262 }  // logging_win
    263