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