Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / test / logging / win / log_file_printer.cc
blob943712aeddceb80f0c7e76467b45910e68f95f09
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.
5 #include "chrome/test/logging/win/log_file_printer.h"
7 #include <windows.h>
8 #include <objbase.h>
10 #include <iomanip>
11 #include <ios>
12 #include <ostream>
13 #include <sstream>
15 #include "base/basictypes.h"
16 #include "base/compiler_specific.h"
17 #include "base/logging.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_piece.h"
20 #include "base/time/time.h"
21 #include "base/trace_event/trace_event.h"
22 #include "chrome/test/logging/win/log_file_reader.h"
24 namespace {
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;
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);
65 *out << filename << '(' << line << ')';
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;
87 class EventPrinter : public logging_win::LogFileDelegate {
88 public:
89 explicit EventPrinter(std::ostream* out);
90 ~EventPrinter() override;
92 void OnUnknownEvent(const EVENT_TRACE* event) override;
94 void OnUnparsableEvent(const EVENT_TRACE* event) override;
96 void OnFileHeader(const EVENT_TRACE* event,
97 const TRACE_LOGFILE_HEADER* header) override;
99 void OnLogMessage(const EVENT_TRACE* event,
100 logging::LogSeverity severity,
101 const base::StringPiece& message) override;
103 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;
111 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;
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);
126 std::ostream* out_;
127 DISALLOW_COPY_AND_ASSIGN(EventPrinter);
130 EventPrinter::EventPrinter(std::ostream* out)
131 : out_(out) {
134 EventPrinter::~EventPrinter() {
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);
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;
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_ << "] ";
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) << ")";
178 void EventPrinter::OnUnknownEvent(const EVENT_TRACE* event) {
179 base::StringPiece empty;
180 PrintEventContext(event, empty, empty);
181 PrintBadEvent(event, "unsupported event");
184 void EventPrinter::OnUnparsableEvent(const EVENT_TRACE* event) {
185 base::StringPiece empty;
186 PrintEventContext(event, empty, empty);
187 PrintBadEvent(event, "parse error");
190 void EventPrinter::OnFileHeader(const EVENT_TRACE* event,
191 const TRACE_LOGFILE_HEADER* header) {
192 base::StringPiece empty;
193 PrintEventContext(event, empty, empty);
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;
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;
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;
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;
240 } // namespace
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);