Index: chrome/test/logging/win/log_file_printer.cc |
diff --git a/chrome/test/logging/win/log_file_printer.cc b/chrome/test/logging/win/log_file_printer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..02d525511e426745087d26c67da902de6abb012b |
--- /dev/null |
+++ b/chrome/test/logging/win/log_file_printer.cc |
@@ -0,0 +1,248 @@ |
+// Copyright (c) 2012 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 "chrome/test/logging/win/log_file_printer.h" |
+ |
+#include <windows.h> |
+#include <objbase.h> |
+ |
+#include <ios> |
+#include <iomanip> |
+#include <ostream> |
+#include <sstream> |
+ |
+#include "base/basictypes.h" |
+#include "base/compiler_specific.h" |
+#include "base/debug/trace_event.h" |
+#include "base/logging.h" |
+#include "base/string_number_conversions.h" |
+#include "base/string_piece.h" |
+#include "base/time.h" |
+#include "chrome/test/logging/win/log_file_reader.h" |
+ |
+namespace { |
+ |
+// TODO(grt) This duplicates private behavior in base/logging.cc's |
+// LogMessage::Init. That behavior should be exposed and used here (possibly |
+// by moving this function to logging.cc, making it use log_severity_names, and |
+// publishing it in logging.h with BASE_EXPORT). |
+void WriteSeverityToStream(logging::LogSeverity severity, std::ostream* out) { |
+ switch (severity) { |
+ case logging::LOG_INFO: |
+ *out << "INFO"; |
+ break; |
+ case logging::LOG_WARNING: |
+ *out << "WARNING"; |
+ break; |
+ case logging::LOG_ERROR: |
+ *out << "ERROR"; |
+ break; |
+ case logging::LOG_ERROR_REPORT: |
+ *out << "ERROR_REPORT"; |
+ break; |
+ case logging::LOG_FATAL: |
+ *out << "FATAL"; |
+ break; |
+ default: |
+ if (severity < 0) |
+ *out << "VERBOSE" << -severity; |
+ else |
+ NOTREACHED(); |
+ break; |
+ } |
+} |
+ |
+// TODO(grt) This duplicates private behavior in base/logging.cc's |
+// LogMessage::Init. That behavior should be exposed and used here (possibly |
+// by moving this function to logging.cc and publishing it in logging.h with |
+// BASE_EXPORT). |
+void WriteLocationToStream(const base::StringPiece& file, |
+ int line, |
+ std::ostream* out) { |
+ base::StringPiece filename(file); |
+ size_t last_slash_pos = filename.find_last_of("\\/"); |
+ if (last_slash_pos != base::StringPiece::npos) |
+ filename.remove_prefix(last_slash_pos + 1); |
+ |
+ *out << filename << '(' << line << ')'; |
+} |
+ |
+// Returns a pretty string for the trace event types that appear in ETW logs. |
+const char* GetTraceTypeString(char event_type) { |
+ switch (event_type) { |
+ case TRACE_EVENT_PHASE_BEGIN: |
+ return "BEGIN"; |
+ break; |
+ case TRACE_EVENT_PHASE_END: |
+ return "END"; |
+ break; |
+ case TRACE_EVENT_PHASE_INSTANT: |
+ return "INSTANT"; |
+ break; |
+ default: |
+ NOTREACHED(); |
+ return ""; |
+ break; |
+ } |
+} |
+ |
+class EventPrinter : public logging_win::LogFileDelegate { |
+ public: |
+ explicit EventPrinter(std::ostream* out); |
+ virtual ~EventPrinter(); |
+ |
+ virtual void OnUnknownEvent(const EVENT_TRACE* event) OVERRIDE; |
+ |
+ virtual void OnUnparsableEvent(const EVENT_TRACE* event) OVERRIDE; |
+ |
+ virtual void OnFileHeader(const EVENT_TRACE* event, |
+ const TRACE_LOGFILE_HEADER* header) OVERRIDE; |
+ |
+ virtual void OnLogMessage(const EVENT_TRACE* event, |
+ logging::LogSeverity severity, |
+ const base::StringPiece& message) OVERRIDE; |
+ |
+ virtual void OnLogMessageFull(const EVENT_TRACE* event, |
+ logging::LogSeverity severity, |
+ DWORD stack_depth, |
+ const intptr_t* backtrace, |
+ int line, |
+ const base::StringPiece& file, |
+ const base::StringPiece& message) OVERRIDE; |
+ |
+ virtual void OnTraceEvent(const EVENT_TRACE* event, |
+ const base::StringPiece& name, |
+ char type, |
+ intptr_t id, |
+ const base::StringPiece& extra, |
+ DWORD stack_depth, |
+ const intptr_t* backtrace) OVERRIDE; |
+ |
+ private: |
+ void PrintTimeStamp(LARGE_INTEGER time_stamp); |
+ void PrintEventContext(const EVENT_TRACE* event, |
+ const base::StringPiece& level, |
+ const base::StringPiece& context); |
+ void PrintBadEvent(const EVENT_TRACE* event, const base::StringPiece& error); |
+ |
+ std::ostream* out_; |
+ DISALLOW_COPY_AND_ASSIGN(EventPrinter); |
+}; |
+ |
+EventPrinter::EventPrinter(std::ostream* out) |
+ : out_(out) { |
+} |
+ |
+EventPrinter::~EventPrinter() { |
+} |
+ |
+void EventPrinter::PrintTimeStamp(LARGE_INTEGER time_stamp) { |
+ FILETIME event_time = {}; |
+ base::Time::Exploded time_exploded = {}; |
+ event_time.dwLowDateTime = time_stamp.LowPart; |
+ event_time.dwHighDateTime = time_stamp.HighPart; |
+ base::Time::FromFileTime(event_time).LocalExplode(&time_exploded); |
+ |
+ *out_ << std::setfill('0') |
+ << std::setw(2) << time_exploded.month |
+ << std::setw(2) << time_exploded.day_of_month |
+ << '/' |
+ << std::setw(2) << time_exploded.hour |
+ << std::setw(2) << time_exploded.minute |
+ << std::setw(2) << time_exploded.second |
+ << '.' |
+ << std::setw(3) << time_exploded.millisecond; |
+} |
+ |
+// Prints the context info at the start of each line: pid, tid, time, etc. |
+void EventPrinter::PrintEventContext(const EVENT_TRACE* event, |
+ const base::StringPiece& level, |
+ const base::StringPiece& context) { |
+ *out_ << '[' << event->Header.ProcessId << ':' |
+ << event->Header.ThreadId << ':'; |
+ PrintTimeStamp(event->Header.TimeStamp); |
+ if (!level.empty()) |
+ *out_ << ':' << level; |
+ if (!context.empty()) |
+ *out_ << ':' << context; |
+ *out_ << "] "; |
+} |
+ |
+// Prints a useful message for events that can't be otherwise printed. |
+void EventPrinter::PrintBadEvent(const EVENT_TRACE* event, |
+ const base::StringPiece& error) { |
+ wchar_t guid[64]; |
+ StringFromGUID2(event->Header.Guid, &guid[0], arraysize(guid)); |
+ *out_ << error << " (class=" << guid << ", type=" |
+ << static_cast<int>(event->Header.Class.Type) << ")"; |
+} |
+ |
+void EventPrinter::OnUnknownEvent(const EVENT_TRACE* event) { |
+ base::StringPiece empty; |
+ PrintEventContext(event, empty, empty); |
+ PrintBadEvent(event, "unsupported event"); |
+} |
+ |
+void EventPrinter::OnUnparsableEvent(const EVENT_TRACE* event) { |
+ base::StringPiece empty; |
+ PrintEventContext(event, empty, empty); |
+ PrintBadEvent(event, "parse error"); |
+} |
+ |
+void EventPrinter::OnFileHeader(const EVENT_TRACE* event, |
+ const TRACE_LOGFILE_HEADER* header) { |
+ base::StringPiece empty; |
+ PrintEventContext(event, empty, empty); |
+ |
+ *out_ << "Log captured from Windows " |
+ << static_cast<int>(header->VersionDetail.MajorVersion) << '.' |
+ << static_cast<int>(header->VersionDetail.MinorVersion) << '.' |
+ << static_cast<int>(header->VersionDetail.SubVersion) << '.' |
+ << static_cast<int>(header->VersionDetail.SubMinorVersion) |
+ << ". " << header->EventsLost << " events lost, " |
+ << header->BuffersLost << " buffers lost." << std::endl; |
+} |
+ |
+void EventPrinter::OnLogMessage(const EVENT_TRACE* event, |
+ logging::LogSeverity severity, |
+ const base::StringPiece& message) { |
+ std::ostringstream level_stream; |
+ WriteSeverityToStream(severity, &level_stream); |
+ PrintEventContext(event, level_stream.str(), base::StringPiece()); |
+ *out_ << message << std::endl; |
+} |
+ |
+void EventPrinter::OnLogMessageFull(const EVENT_TRACE* event, |
+ logging::LogSeverity severity, |
+ DWORD stack_depth, |
+ const intptr_t* backtrace, |
+ int line, |
+ const base::StringPiece& file, |
+ const base::StringPiece& message) { |
+ std::ostringstream level_stream; |
+ std::ostringstream location_stream; |
+ WriteSeverityToStream(severity, &level_stream); |
+ WriteLocationToStream(file, line, &location_stream); |
+ PrintEventContext(event, level_stream.str(), location_stream.str()); |
+ *out_ << message << std::endl; |
+} |
+ |
+void EventPrinter::OnTraceEvent(const EVENT_TRACE* event, |
+ const base::StringPiece& name, |
+ char type, |
+ intptr_t id, |
+ const base::StringPiece& extra, |
+ DWORD stack_depth, |
+ const intptr_t* backtrace) { |
+ PrintEventContext(event, GetTraceTypeString(type), base::StringPiece()); |
+ *out_ << name << " (id=" << std::hex << id << ") " << extra << std::endl; |
+} |
+ |
+} // namespace |
+ |
+void logging_win::PrintLogFile(const FilePath& log_file, |
+ std::ostream* out) { |
+ EventPrinter printer(out); |
+ logging_win::ReadLogFile(log_file, &printer); |
+} |