OLD | NEW |
---|---|
(Empty) | |
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/base/log_file_reader_win.h" | |
6 | |
7 #include "base/debug/trace_event_win.h" | |
8 #include "base/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/base/mof_data_parser_win.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 FilePath& log_file, LogFileDelegate* delegate); | |
69 | |
70 private: | |
71 // An implementation of a trace consumer that delegates to a given (at | |
72 // compile-time) event processing function. | |
73 template<void (*ProcessEventFn)(EVENT_TRACE*)> | |
74 class TraceConsumer | |
75 : public base::win::EtwTraceConsumerBase<TraceConsumer<ProcessEventFn> > { | |
76 public: | |
77 TraceConsumer() { } | |
78 static void ProcessEvent(EVENT_TRACE* event) { (*ProcessEventFn)(event); } | |
79 private: | |
80 DISALLOW_COPY_AND_ASSIGN(TraceConsumer); | |
81 }; | |
82 | |
83 // Delegates to DispatchEvent() of the current LogDumper instance. | |
84 static void ProcessEvent(EVENT_TRACE* event); | |
85 | |
86 // Handlers for the supported event types. | |
87 bool OnLogMessageEvent(const EVENT_TRACE* event); | |
88 bool OnLogMessageFullEvent(const EVENT_TRACE* event); | |
89 bool OnTraceEvent(const EVENT_TRACE* event); | |
90 bool OnFileHeader(const EVENT_TRACE* event); | |
91 | |
92 // Parses an event and passes it along to the delegate for processing. | |
93 void DispatchEvent(const EVENT_TRACE* event); | |
94 | |
95 // Reads the file using a trace consumer. |ProcessEvent| will be invoked for | |
96 // each event in the file. | |
97 void Read(const FilePath& log_file); | |
98 | |
99 // Protects use of the class; only one instance may be live at a time. | |
100 static base::LazyInstance<base::Lock>::Leaky reader_lock_; | |
101 | |
102 // The currently living instance. | |
103 static LogFileReader* instance_; | |
104 | |
105 // The delegate to be notified of events. | |
106 LogFileDelegate* delegate_; | |
107 }; | |
108 | |
109 // static | |
110 base::LazyInstance<base::Lock>::Leaky LogFileReader::reader_lock_ = | |
111 LAZY_INSTANCE_INITIALIZER; | |
112 | |
113 // static | |
114 LogFileReader* LogFileReader::instance_ = NULL; | |
115 | |
116 LogFileReader::LogFileReader(LogFileDelegate* delegate) | |
117 : delegate_(delegate) { | |
118 DCHECK(instance_ == NULL); | |
119 DCHECK(delegate != NULL); | |
120 instance_ = this; | |
121 } | |
122 | |
123 LogFileReader::~LogFileReader() { | |
124 DCHECK_EQ(instance_, this); | |
125 instance_ = NULL; | |
126 } | |
127 | |
128 // static | |
129 void LogFileReader::ProcessEvent(EVENT_TRACE* event) { | |
130 if (instance_ != NULL) | |
131 instance_->DispatchEvent(event); | |
132 } | |
133 | |
134 bool LogFileReader::OnLogMessageEvent(const EVENT_TRACE* event) { | |
135 base::StringPiece message; | |
136 MofDataParser parser(event); | |
137 if (parser.ReadString(&message) && parser.empty()) { | |
138 delegate_->OnLogMessage(event, | |
139 EventLevelToSeverity(event->Header.Class.Level), | |
140 message); | |
141 return true; | |
142 } | |
143 return false; | |
144 } | |
145 | |
146 bool LogFileReader::OnLogMessageFullEvent(const EVENT_TRACE* event) { | |
147 DWORD stack_depth = 0; | |
148 const intptr_t* backtrace = NULL; | |
149 int line = 0; | |
150 base::StringPiece file; | |
151 base::StringPiece message; | |
152 MofDataParser parser(event); | |
153 | |
154 if (parser.ReadDWORD(&stack_depth) && | |
erikwright (departed)
2012/03/09 18:50:33
Presumably this maps to some writing code somewher
grt (UTC plus 2)
2012/03/09 20:38:57
Done.
| |
155 parser.ReadPointerArray(stack_depth, &backtrace) && | |
156 parser.ReadInt(&line) && | |
157 parser.ReadString(&file) && | |
158 parser.ReadString(&message) && | |
159 parser.empty()) { | |
160 delegate_->OnLogMessageFull(event, | |
161 EventLevelToSeverity(event->Header.Class.Level), stack_depth, backtrace, | |
162 line, file, message); | |
163 return true; | |
164 } | |
165 return false; | |
166 } | |
167 | |
168 bool LogFileReader::OnTraceEvent(const EVENT_TRACE* event) { | |
169 MofDataParser parser(event); | |
170 base::StringPiece name; | |
171 intptr_t id = 0; | |
172 base::StringPiece extra; | |
173 DWORD stack_depth = 0; | |
174 const intptr_t* backtrace = NULL; | |
175 | |
176 if (parser.ReadString(&name) && | |
erikwright (departed)
2012/03/09 18:50:33
Ditto.
grt (UTC plus 2)
2012/03/09 20:38:57
Done.
| |
177 parser.ReadPointer(&id) && | |
178 parser.ReadString(&extra) && | |
179 (parser.empty() || | |
180 parser.ReadDWORD(&stack_depth) && | |
181 parser.ReadPointerArray(stack_depth, &backtrace) && | |
182 parser.empty())) { | |
183 delegate_->OnTraceEvent(event, name, | |
184 EventTypeToTraceType(event->Header.Class.Type), id, extra, stack_depth, | |
185 backtrace); | |
186 return true; | |
187 } | |
188 return false; | |
189 } | |
190 | |
191 bool LogFileReader::OnFileHeader(const EVENT_TRACE* event) { | |
192 MofDataParser parser(event); | |
193 const TRACE_LOGFILE_HEADER* header = NULL; | |
194 | |
195 if (parser.ReadStructure(&header)) { | |
196 delegate_->OnFileHeader(event, header); | |
197 return true; | |
198 } | |
199 return false; | |
200 } | |
201 | |
202 void LogFileReader::DispatchEvent(const EVENT_TRACE* event) { | |
203 bool parsed = true; | |
204 | |
205 if (IsEqualGUID(event->Header.Guid, logging::kLogEventId)) { | |
206 if (event->Header.Class.Type == logging::LOG_MESSAGE) | |
207 parsed = OnLogMessageEvent(event); | |
208 else if (event->Header.Class.Type == logging::LOG_MESSAGE_FULL) | |
209 parsed = OnLogMessageFullEvent(event); | |
210 } else if (IsEqualGUID(event->Header.Guid, base::debug::kTraceEventClass32)) { | |
211 parsed = OnTraceEvent(event); | |
212 } else if (IsEqualGUID(event->Header.Guid, EventTraceGuid)) { | |
213 parsed = OnFileHeader(event); | |
214 } else { | |
215 DCHECK(parsed); | |
216 delegate_->OnUnknownEvent(event); | |
217 } | |
218 if (!parsed) | |
219 delegate_->OnUnparsableEvent(event); | |
220 } | |
221 | |
222 void LogFileReader::Read(const FilePath& log_file) { | |
223 TraceConsumer<&ProcessEvent> consumer; | |
224 HRESULT hr = S_OK; | |
225 | |
226 hr = consumer.OpenFileSession(log_file.value().c_str()); | |
227 if (FAILED(hr)) { | |
228 LOG(ERROR) << "Failed to open session for log file " << log_file.value() | |
229 << "; hr=" << std::hex << hr; | |
230 } else { | |
231 consumer.Consume(); | |
232 consumer.Close(); | |
233 } | |
234 } | |
235 | |
236 // static | |
237 void LogFileReader::ReadFile(const FilePath& log_file, | |
238 LogFileDelegate* delegate) { | |
239 base::AutoLock lock(reader_lock_.Get()); | |
240 | |
241 LogFileReader(delegate).Read(log_file); | |
242 } | |
243 | |
244 } // namespace | |
245 | |
246 LogFileDelegate::LogFileDelegate() { | |
247 } | |
248 | |
249 LogFileDelegate::~LogFileDelegate() { | |
250 } | |
251 | |
252 void ReadLogFile(const FilePath& log_file, LogFileDelegate* delegate) { | |
253 DCHECK(delegate); | |
254 LogFileReader::ReadFile(log_file, delegate); | |
255 } | |
256 | |
257 } // logging_win | |
OLD | NEW |