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_printer.h"
      6 
      7 #include <windows.h>
      8 #include <objbase.h>
      9 
     10 #include <iomanip>
     11 #include <ios>
     12 #include <ostream>
     13 #include <sstream>
     14 
     15 #include "base/basictypes.h"
     16 #include "base/compiler_specific.h"
     17 #include "base/debug/trace_event.h"
     18 #include "base/logging.h"
     19 #include "base/strings/string_number_conversions.h"
     20 #include "base/strings/string_piece.h"
     21 #include "base/time/time.h"
     22 #include "chrome/test/logging/win/log_file_reader.h"
     23 
     24 namespace {
     25 
     26 // TODO(grt) This duplicates private behavior in base/logging.cc's
     27 // LogMessage::Init.  That behavior should be exposed and used here (possibly
     28 // by moving this function to logging.cc, making it use log_severity_names, and
     29 // publishing it in logging.h with BASE_EXPORT).
     30 void WriteSeverityToStream(logging::LogSeverity severity, std::ostream* out) {
     31   switch (severity) {
     32     case logging::LOG_INFO:
     33       *out << "INFO";
     34       break;
     35     case logging::LOG_WARNING:
     36       *out << "WARNING";
     37       break;
     38     case logging::LOG_ERROR:
     39       *out << "ERROR";
     40       break;
     41     case logging::LOG_FATAL:
     42       *out << "FATAL";
     43       break;
     44     default:
     45       if (severity < 0)
     46         *out << "VERBOSE" << -severity;
     47       else
     48         NOTREACHED();
     49       break;
     50   }
     51 }
     52 
     53 // TODO(grt) This duplicates private behavior in base/logging.cc's
     54 // LogMessage::Init.  That behavior should be exposed and used here (possibly
     55 // by moving this function to logging.cc and publishing it in logging.h with
     56 // BASE_EXPORT).
     57 void WriteLocationToStream(const base::StringPiece& file,
     58                            int line,
     59                            std::ostream* out) {
     60   base::StringPiece filename(file);
     61   size_t last_slash_pos = filename.find_last_of("\\/");
     62   if (last_slash_pos != base::StringPiece::npos)
     63     filename.remove_prefix(last_slash_pos + 1);
     64 
     65   *out << filename << '(' << line << ')';
     66 }
     67 
     68 // Returns a pretty string for the trace event types that appear in ETW logs.
     69 const char* GetTraceTypeString(char event_type) {
     70   switch (event_type) {
     71     case TRACE_EVENT_PHASE_BEGIN:
     72       return "BEGIN";
     73       break;
     74     case TRACE_EVENT_PHASE_END:
     75       return "END";
     76       break;
     77     case TRACE_EVENT_PHASE_INSTANT:
     78       return "INSTANT";
     79       break;
     80     default:
     81       NOTREACHED();
     82       return "";
     83       break;
     84   }
     85 }
     86 
     87 class EventPrinter : public logging_win::LogFileDelegate {
     88  public:
     89   explicit EventPrinter(std::ostream* out);
     90   virtual ~EventPrinter();
     91 
     92   virtual void OnUnknownEvent(const EVENT_TRACE* event) OVERRIDE;
     93 
     94   virtual void OnUnparsableEvent(const EVENT_TRACE* event) OVERRIDE;
     95 
     96   virtual void OnFileHeader(const EVENT_TRACE* event,
     97                             const TRACE_LOGFILE_HEADER* header) OVERRIDE;
     98 
     99   virtual void OnLogMessage(const EVENT_TRACE* event,
    100                             logging::LogSeverity severity,
    101                             const base::StringPiece& message) OVERRIDE;
    102 
    103   virtual void OnLogMessageFull(const EVENT_TRACE* event,
    104                                 logging::LogSeverity severity,
    105                                 DWORD stack_depth,
    106                                 const intptr_t* backtrace,
    107                                 int line,
    108                                 const base::StringPiece& file,
    109                                 const base::StringPiece& message) OVERRIDE;
    110 
    111   virtual void OnTraceEvent(const EVENT_TRACE* event,
    112                             const base::StringPiece& name,
    113                             char type,
    114                             intptr_t id,
    115                             const base::StringPiece& extra,
    116                             DWORD stack_depth,
    117                             const intptr_t* backtrace) OVERRIDE;
    118 
    119  private:
    120   void PrintTimeStamp(LARGE_INTEGER time_stamp);
    121   void PrintEventContext(const EVENT_TRACE* event,
    122                          const base::StringPiece& level,
    123                          const base::StringPiece& context);
    124   void PrintBadEvent(const EVENT_TRACE* event, const base::StringPiece& error);
    125 
    126   std::ostream* out_;
    127   DISALLOW_COPY_AND_ASSIGN(EventPrinter);
    128 };
    129 
    130 EventPrinter::EventPrinter(std::ostream* out)
    131     : out_(out) {
    132 }
    133 
    134 EventPrinter::~EventPrinter() {
    135 }
    136 
    137 void EventPrinter::PrintTimeStamp(LARGE_INTEGER time_stamp) {
    138   FILETIME event_time = {};
    139   base::Time::Exploded time_exploded = {};
    140   event_time.dwLowDateTime = time_stamp.LowPart;
    141   event_time.dwHighDateTime = time_stamp.HighPart;
    142   base::Time::FromFileTime(event_time).LocalExplode(&time_exploded);
    143 
    144   *out_ << std::setfill('0')
    145         << std::setw(2) << time_exploded.month
    146         << std::setw(2) << time_exploded.day_of_month
    147         << '/'
    148         << std::setw(2) << time_exploded.hour
    149         << std::setw(2) << time_exploded.minute
    150         << std::setw(2) << time_exploded.second
    151         << '.'
    152         << std::setw(3) << time_exploded.millisecond;
    153 }
    154 
    155 // Prints the context info at the start of each line: pid, tid, time, etc.
    156 void EventPrinter::PrintEventContext(const EVENT_TRACE* event,
    157                                      const base::StringPiece& level,
    158                                      const base::StringPiece& context) {
    159   *out_ << '[' << event->Header.ProcessId << ':'
    160         << event->Header.ThreadId << ':';
    161   PrintTimeStamp(event->Header.TimeStamp);
    162   if (!level.empty())
    163     *out_ << ':' << level;
    164   if (!context.empty())
    165     *out_ << ':' << context;
    166   *out_ << "] ";
    167 }
    168 
    169 // Prints a useful message for events that can't be otherwise printed.
    170 void EventPrinter::PrintBadEvent(const EVENT_TRACE* event,
    171                                  const base::StringPiece& error) {
    172   wchar_t guid[64];
    173   StringFromGUID2(event->Header.Guid, &guid[0], arraysize(guid));
    174   *out_ << error << " (class=" << guid << ", type="
    175        << static_cast<int>(event->Header.Class.Type) << ")";
    176 }
    177 
    178 void EventPrinter::OnUnknownEvent(const EVENT_TRACE* event) {
    179   base::StringPiece empty;
    180   PrintEventContext(event, empty, empty);
    181   PrintBadEvent(event, "unsupported event");
    182 }
    183 
    184 void EventPrinter::OnUnparsableEvent(const EVENT_TRACE* event) {
    185   base::StringPiece empty;
    186   PrintEventContext(event, empty, empty);
    187   PrintBadEvent(event, "parse error");
    188 }
    189 
    190 void EventPrinter::OnFileHeader(const EVENT_TRACE* event,
    191                                 const TRACE_LOGFILE_HEADER* header) {
    192   base::StringPiece empty;
    193   PrintEventContext(event, empty, empty);
    194 
    195   *out_ << "Log captured from Windows "
    196         << static_cast<int>(header->VersionDetail.MajorVersion) << '.'
    197         << static_cast<int>(header->VersionDetail.MinorVersion) << '.'
    198         << static_cast<int>(header->VersionDetail.SubVersion) << '.'
    199         << static_cast<int>(header->VersionDetail.SubMinorVersion)
    200         << ".  " << header->EventsLost << " events lost, "
    201         << header->BuffersLost << " buffers lost." << std::endl;
    202 }
    203 
    204 void EventPrinter::OnLogMessage(const EVENT_TRACE* event,
    205                                 logging::LogSeverity severity,
    206                                 const base::StringPiece& message) {
    207   std::ostringstream level_stream;
    208   WriteSeverityToStream(severity, &level_stream);
    209   PrintEventContext(event, level_stream.str(), base::StringPiece());
    210   *out_ << message << std::endl;
    211 }
    212 
    213 void EventPrinter::OnLogMessageFull(const EVENT_TRACE* event,
    214                                     logging::LogSeverity severity,
    215                                     DWORD stack_depth,
    216                                     const intptr_t* backtrace,
    217                                     int line,
    218                                     const base::StringPiece& file,
    219                                     const base::StringPiece& message) {
    220   std::ostringstream level_stream;
    221   std::ostringstream location_stream;
    222   WriteSeverityToStream(severity, &level_stream);
    223   WriteLocationToStream(file, line, &location_stream);
    224   PrintEventContext(event, level_stream.str(), location_stream.str());
    225   *out_ << message << std::endl;
    226 }
    227 
    228 void EventPrinter::OnTraceEvent(const EVENT_TRACE* event,
    229                                 const base::StringPiece& name,
    230                                 char type,
    231                                 intptr_t id,
    232                                 const base::StringPiece& extra,
    233                                 DWORD stack_depth,
    234                                 const intptr_t* backtrace) {
    235   PrintEventContext(event, GetTraceTypeString(type), base::StringPiece());
    236   *out_ << name << " (id=0x" << std::hex << id << std::dec << ") " << extra
    237         << std::endl;
    238 }
    239 
    240 }  // namespace
    241 
    242 void logging_win::PrintLogFile(const base::FilePath& log_file,
    243                                std::ostream* out) {
    244   EventPrinter printer(out);
    245   logging_win::ReadLogFile(log_file, &printer);
    246 }
    247