Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(130)

Side by Side Diff: chrome/test/base/file_logger_win.cc

Issue 9584017: New test infrastructure for producing verbose logs in failing tests. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: capture trace events as well Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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/file_logger_win.h"
6
7 #include <windows.h>
8 #include <evntrace.h>
9 #include <guiddef.h>
10 #include <objbase.h> // for StringFromGUID2
robertshield 2012/03/05 19:20:54 any reason for the comment?
grt (UTC plus 2) 2012/03/06 03:24:57 Not really. Removed.
11
12 #include <iomanip>
13 #include <ios> // For std::hex
14
15 #include "base/debug/trace_event_win.h"
16 #include "base/logging.h"
17 #include "base/file_path.h"
18 #include "base/logging_win.h"
19 #include "base/memory/scoped_ptr.h"
20 #include "base/string_piece.h"
21 #include "base/string16.h"
22 #include "base/utf_string_conversions.h"
23 #include "base/win/event_trace_consumer.h"
24 #include "base/win/registry.h"
25 #include "chrome/common/env_vars.h"
26
27 namespace {
28
29 bool g_is_initialized = false;
30
31 const wchar_t kChromeTestSession[] = L"chrome_tests";
32
33 // From chrome_tab.cc: {0562BFC3-2550-45b4-BD8E-A310583D3A6F}
34 const GUID kChromeFrameProvider =
35 { 0x562bfc3, 0x2550, 0x45b4,
36 { 0xbd, 0x8e, 0xa3, 0x10, 0x58, 0x3d, 0x3a, 0x6f } };
37
38 // From chrome/common/logging_chrome.cc: {7FE69228-633E-4f06-80C1-527FEA23E3A7}
39 const GUID kChromeTraceProviderName =
40 { 0x7fe69228, 0x633e, 0x4f06,
41 { 0x80, 0xc1, 0x52, 0x7f, 0xea, 0x23, 0xe3, 0xa7 } };
42
43 // {81729947-CD2A-49e6-8885-785429F339F5}
44 const GUID kChromeTestsProvider =
45 { 0x81729947, 0xcd2a, 0x49e6,
46 { 0x88, 0x85, 0x78, 0x54, 0x29, 0xf3, 0x39, 0xf5 } };
47
48 // The configurations for the supported providers. This must be in sync with
49 // FileLogger::EventProviderBits.
50 const struct {
51 const GUID* provider_name;
52 uint8 level;
53 uint32 flags;
54 } kProviders[] = {
55 { &kChromeTraceProviderName, 255, 0 },
56 { &kChromeFrameProvider, 255, 0 },
57 { &kChromeTestsProvider, 255, 0 },
58 { &base::debug::kChromeTraceProviderName, 255, 0 }
59 };
robertshield 2012/03/05 19:20:54 COMPILE_ASSERT on the arraysize vs the enum in the
grt (UTC plus 2) 2012/03/06 03:24:57 Kinda done. I checked it against the bitfield of
60
61 const HKEY kEnvironmentRoot = HKEY_LOCAL_MACHINE;
62 const wchar_t kEnvironmentKey[] =
63 L"SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment";
64 const wchar_t kEnvironment[] = L"Environment";
65 unsigned int kBroadcastTimeoutMilliseconds = 2 * 1000;
66
67
68 // Writes a timestamp.
69 void WriteTimeStamp(LARGE_INTEGER time_stamp, std::ostream& out) {
robertshield 2012/03/05 19:20:54 don't use non-const references
grt (UTC plus 2) 2012/03/06 03:24:57 In the case of streams, I think it makes more sens
70 // Get a nice SYSTEMTIME from the time_stamp.
71 FILETIME event_time = {};
72 event_time.dwLowDateTime = time_stamp.LowPart;
73 event_time.dwHighDateTime = time_stamp.HighPart;
74 SYSTEMTIME system_time = {};
75 FileTimeToSystemTime(&event_time, &system_time);
76
77 // SYSTEMTIME only has millisecond accuracy. Do some conversions and math to
78 // get the sub-second time (number of 100ns ticks).
79 system_time.wMilliseconds = 0;
80 FILETIME coarse_event_time = {};
81 SystemTimeToFileTime(&system_time, &coarse_event_time);
82 ULARGE_INTEGER coarse_value;
83 coarse_value.HighPart = coarse_event_time.dwHighDateTime;
84 coarse_value.LowPart = coarse_event_time.dwLowDateTime;
85 coarse_value.QuadPart = time_stamp.QuadPart - coarse_value.QuadPart;
robertshield 2012/03/05 19:20:54 consider mentioning that ULARGE_INTEGER is a union
grt (UTC plus 2) 2012/03/06 03:24:57 Switched to using base/time.h's facilities, giving
86 DCHECK_EQ(coarse_value.HighPart, static_cast<DWORD>(0));
87 DCHECK_LT(coarse_value.LowPart, static_cast<DWORD>(10000000));
88
89 out << std::setfill('0')
90 << std::setw(2) << system_time.wMonth
91 << std::setw(2) << system_time.wDay
92 << '/'
93 << std::setw(2) << system_time.wHour
94 << std::setw(2) << system_time.wMinute
95 << std::setw(2) << system_time.wSecond
96 << '.'
97 << std::setw(7) << coarse_value.LowPart;
98 }
99
100 // Converts an ETW level created by logging::LogEventProvider back to its
101 // corresponding severity.
erikwright (departed) 2012/03/05 19:55:30 I suspect this corresponds to an inverse switch st
102 logging::LogSeverity EventLevelToSeverity(uint8 level) {
103 switch (level) {
104 case TRACE_LEVEL_NONE:
105 NOTREACHED();
106 case TRACE_LEVEL_FATAL:
107 return logging::LOG_FATAL;
108 case TRACE_LEVEL_ERROR:
109 return logging::LOG_ERROR;
110 case TRACE_LEVEL_WARNING:
111 return logging::LOG_WARNING;
112 case TRACE_LEVEL_INFORMATION:
113 return logging::LOG_INFO;
114 default:
115 // Trace levels above information correspond to negative severity levels,
116 // which are used for VLOG verbosity levels.
117 return TRACE_LEVEL_INFORMATION - level;
118 }
119 }
120
121 // Writes a severity level to the stream a la LogMessage::Init.
122 void WriteSeverity(logging::LogSeverity severity, std::ostream& out) {
erikwright (departed) 2012/03/05 19:55:30 This is how base/logging.h does it: http://code.g
123 switch (severity) {
124 case logging::LOG_INFO:
125 out << "INFO";
126 break;
127 case logging::LOG_WARNING:
128 out << "WARNING";
129 break;
130 case logging::LOG_ERROR:
131 out << "ERROR";
132 break;
133 case logging::LOG_ERROR_REPORT:
134 out << "ERROR_REPORT";
135 break;
136 case logging::LOG_FATAL:
137 out << "FATAL";
138 break;
139 default:
140 if (severity < 0)
141 out << "VERBOSE" << -severity;
142 else
143 NOTREACHED();
144 break;
145 }
146 }
147
148 // A helper class that dumps a log file to an output stream. Only one may be
149 // in use at a time.
150 class LogDumper {
151 public:
152 // Dump |log_file| to |out|.
153 static void DumpLog(const FilePath& log_file, std::ostream& out);
154
155 private:
156 // An implementation of a trace consumer that delegates to a given (at
157 // compile-time) event processing function.
158 template<void (*ProcessEventFn)(EVENT_TRACE*)>
159 class TraceConsumer
160 : public base::win::EtwTraceConsumerBase<TraceConsumer<ProcessEventFn> > {
robertshield 2012/03/05 19:20:54 template abuse alert.. template abuse alert.. It
robertshield 2012/03/05 19:57:07 Taking a look at the implementation of EtwTraceCon
grt (UTC plus 2) 2012/03/06 03:24:57 Thanks. I didn't like the other obvious options (
161 public:
162 TraceConsumer() { }
163 static void ProcessEvent(EVENT_TRACE* event) { (*ProcessEventFn)(event); }
164 private:
165 DISALLOW_COPY_AND_ASSIGN(TraceConsumer);
166 };
167
168 // A parser for Mof data found in an EVENT_TRACE object as formatted by
erikwright (departed) 2012/03/05 19:55:30 I find it shocking that this needs to be written b
169 // Chromium-related classes.
170 class MofDataParser {
171 public:
172 explicit MofDataParser(EVENT_TRACE* event);
173 bool ReadDWORD(DWORD* value) {
174 return ReadPrimitive(value);
175 }
176 bool ReadInt(int* value) {
177 return ReadPrimitive(value);
178 }
179 bool ReadVoidPointer(void** value) {
180 return ReadPrimitive(value);
181 }
182 bool ReadVoidPointerArray(DWORD size, void* const** values) {
183 return ReadPointerArray(size, values);
184 }
185 // Reads an arbitrary data structure within the data.
186 template<typename T> bool ReadStructure(const T** value) {
187 if (length_ < sizeof(**value))
188 return false;
189 *value = reinterpret_cast<const T*>(scan_);
190 Advance(sizeof(**value));
191 return true;
192 }
193 // Reads a null-terminated string from the data. A trailing newline, if
194 // present, is stripped.
195 bool ReadString(base::StringPiece* value);
196 bool empty() { return length_ == 0; }
197
198 private:
199 void Advance(size_t num_bytes) {
200 scan_ += num_bytes;
201 length_ -= num_bytes;
202 }
203 template<typename T> bool ReadPrimitive(T* value) {
204 if (length_ < sizeof(*value))
205 return false;
206 *value = *reinterpret_cast<const T*>(scan_);
207 Advance(sizeof(*value));
208 return true;
209 }
210 template<typename T> bool ReadPointerArray(DWORD size, T* const** values) {
211 if (length_ < sizeof(*values) * size)
212 return false;
213 *values = reinterpret_cast<T* const*>(scan_);
214 Advance(sizeof(*values) * size);
215 return true;
216 }
217
218 const uint8* scan_;
219 uint32 length_;
220 };
221
222 // An interface for handling Mof data.
223 class MofData {
224 public:
225 virtual ~MofData();
226
227 // Parses the data in |event|, returning true on success; false otherwise.
228 virtual bool Initialize(EVENT_TRACE* event) = 0;
229
230 // Writes the event level.
231 virtual bool WriteLevel(uint8 level, std::ostream& out) = 0;
232
233 // Writes context information.
234 virtual void WriteContext(std::ostream& out) = 0;
235
236 // Writes the meat of the data.
237 virtual void WriteData(std::ostream& out) = 0;
238
239 protected:
240 MofData();
241 };
242
243 // A MofData implementation for events created by Chromium's LogEventProvider
244 // when the ENABLE_LOG_MESSAGE_ONLY flag is set.
245 class LogMessageData : public MofData {
246 public:
247 LogMessageData();
248 virtual ~LogMessageData();
249 virtual bool Initialize(EVENT_TRACE* event) OVERRIDE;
250 virtual bool WriteLevel(uint8 level, std::ostream& out) OVERRIDE;
251 virtual void WriteContext(std::ostream& out) OVERRIDE;
252 virtual void WriteData(std::ostream& out) OVERRIDE;
253
254 private:
255 base::StringPiece message_;
256 DISALLOW_COPY_AND_ASSIGN(LogMessageData);
257 };
258
259 // A MofData implementation for events created by Chromium's LogEventProvider
260 // when the ENABLE_LOG_MESSAGE_ONLY flag is not set.
261 class LogMessageFullData : public MofData {
262 public:
263 LogMessageFullData();
264 virtual ~LogMessageFullData();
265 virtual bool Initialize(EVENT_TRACE* event) OVERRIDE;
266 virtual bool WriteLevel(uint8 level, std::ostream& out) OVERRIDE;
267 virtual void WriteContext(std::ostream& out) OVERRIDE;
268 virtual void WriteData(std::ostream& out) OVERRIDE;
269
270 private:
271 DWORD stack_depth_;
272 void *const * backtrace_;
273 int line_;
274 base::StringPiece file_;
275 base::StringPiece message_;
276 DISALLOW_COPY_AND_ASSIGN(LogMessageFullData);
277 };
278
279 // A MofData implementation for events created by Chromium's
280 // TraceEventETWProvider.
281 class TraceEventData : public MofData {
282 public:
283 TraceEventData();
284 virtual ~TraceEventData();
285 virtual bool Initialize(EVENT_TRACE* event) OVERRIDE;
286 virtual bool WriteLevel(uint8 level, std::ostream& out) OVERRIDE;
287 virtual void WriteContext(std::ostream& out) OVERRIDE;
288 virtual void WriteData(std::ostream& out) OVERRIDE;
289
290 private:
291 const char* type_;
292 base::StringPiece name_;
293 void* id_;
294 base::StringPiece extra_;
295 DWORD stack_depth_;
296 void *const * backtrace_;
297 DISALLOW_COPY_AND_ASSIGN(TraceEventData);
298 };
299
300 // A MofData implementation for the TRACE_LOGFILE_HEADER event at the start of
301 // log files.
302 class LogfileHeaderData : public MofData {
303 public:
304 LogfileHeaderData();
305 virtual ~LogfileHeaderData();
306 virtual bool Initialize(EVENT_TRACE* event) OVERRIDE;
307 virtual bool WriteLevel(uint8 level, std::ostream& out) OVERRIDE;
308 virtual void WriteContext(std::ostream& out) OVERRIDE;
309 virtual void WriteData(std::ostream& out) OVERRIDE;
310
311 private:
312 const TRACE_LOGFILE_HEADER* header_;
313 DISALLOW_COPY_AND_ASSIGN(LogfileHeaderData);
314 };
315
316 // A pointer to a function that creates a new instance of some MofData
317 // implementation.
318 typedef MofData* (*MofDataFactoryFn)();
319
320 // Returns a new instance of a MofData implementation.
321 template<class MofDataType> static MofData* CreateMofData() {
322 return new MofDataType();
323 }
324
325 explicit LogDumper(std::ostream& out);
326 ~LogDumper();
327
328 // Returns a factory function to create the MofData implementation
329 // corresponding to an EVENT_TRACE instance of the given event class and type.
330 static MofDataFactoryFn GetMofDataFactory(const GUID& event_class,
331 uint8 type);
332
333 // Delegates to DumpEvent() of the current LogDumper instance.
334 static void ProcessEvent(EVENT_TRACE* event);
335
336 // Dumps the event.
337 void DumpEvent(EVENT_TRACE* event);
338
339 // Consumes all events in |log_file|, dumping them to the output stream.
340 void Consume(const FilePath& log_file);
341
342 // The current instance.
343 static LogDumper* instance_;
344 std::ostream* out_;
345
346 DISALLOW_COPY_AND_ASSIGN(LogDumper);
347 };
348
349 // LogDumper::MofDataParser implementation
350
351 LogDumper::MofDataParser::MofDataParser(EVENT_TRACE* event)
352 : scan_(reinterpret_cast<CONST uint8*>(event->MofData)),
353 length_(event->MofLength) {
354 }
355
356 bool LogDumper::MofDataParser::ReadString(base::StringPiece* value) {
357 const uint8* str_scan = scan_;
358 const uint8* const str_end = str_scan + length_;
359 while (str_scan < str_end && *str_scan != 0)
360 ++str_scan;
361 if (str_scan == str_end)
362 return false;
363 size_t string_length = str_scan - scan_;
364 bool has_trailing_newline = (string_length > 0 && str_scan[-1] == '\n');
365 value->set(reinterpret_cast<const char*>(scan_),
366 has_trailing_newline ? string_length - 1 : string_length);
367 Advance(string_length + 1);
368 return true;
369 }
370
371 // LogDumper::MofData implementation
372
373 LogDumper::MofData::MofData() {
374 }
375
376 LogDumper::MofData::~MofData() {
377 }
378
379 // LogDumper::LogMessageData implementation
380
381 LogDumper::LogMessageData::LogMessageData() {
382 }
383
384 LogDumper::LogMessageData::~LogMessageData() {
385 }
386
387 bool LogDumper::LogMessageData::Initialize(EVENT_TRACE* event) {
388 MofDataParser parser(event);
389 return (parser.ReadString(&message_) &&
390 parser.empty());
391 }
392
393 bool LogDumper::LogMessageData::WriteLevel(uint8 level, std::ostream& out) {
394 WriteSeverity(EventLevelToSeverity(level), out);
395 return true;
396 }
397
398 void LogDumper::LogMessageData::WriteContext(std::ostream& out) {
399 }
400
401 void LogDumper::LogMessageData::WriteData(std::ostream& out) {
402 out << message_;
403 }
404
405 // LogDumper::LogMessageFullData implementation
406
407 LogDumper::LogMessageFullData::LogMessageFullData()
408 : stack_depth_(),
409 backtrace_(),
410 line_() {
411 }
412
413 LogDumper::LogMessageFullData::~LogMessageFullData() {
414 }
415
416 bool LogDumper::LogMessageFullData::Initialize(EVENT_TRACE* event) {
417 MofDataParser parser(event);
418 return (parser.ReadDWORD(&stack_depth_) &&
419 parser.ReadVoidPointerArray(stack_depth_, &backtrace_) &&
420 parser.ReadInt(&line_) &&
421 parser.ReadString(&file_) &&
422 parser.ReadString(&message_) &&
423 parser.empty());
424 }
425
426 bool LogDumper::LogMessageFullData::WriteLevel(uint8 level, std::ostream& out) {
427 WriteSeverity(EventLevelToSeverity(level), out);
428 return true;
429 }
430
431 void LogDumper::LogMessageFullData::WriteContext(std::ostream& out) {
432 // Shamelessly borrowed from base/logging.cc LogMessage::Init()
433 base::StringPiece filename(file_);
434 size_t last_slash_pos = filename.find_last_of("\\/");
435 if (last_slash_pos != base::StringPiece::npos)
436 filename.remove_prefix(last_slash_pos + 1);
437
438 out << filename << '(' << line_ << ')';
439 }
440
441 void LogDumper::LogMessageFullData::WriteData(std::ostream& out) {
442 out << message_;
443 }
444
445 // LogDumper::TraceEventData implementation
446
447 LogDumper::TraceEventData::TraceEventData()
448 : type_(),
449 id_(),
450 stack_depth_(),
451 backtrace_() {
452 }
453
454 LogDumper::TraceEventData::~TraceEventData() {
455 }
456
457 bool LogDumper::TraceEventData::Initialize(EVENT_TRACE* event) {
458 switch (event->Header.Class.Type) {
459 case base::debug::kTraceEventTypeBegin:
460 type_ = "BEGIN";
461 break;
462 case base::debug::kTraceEventTypeEnd:
463 type_ = "END";
464 break;
465 case base::debug::kTraceEventTypeInstant:
466 type_ = "INSTANT";
467 break;
468 default:
469 NOTREACHED();
470 type_ = "";
471 break;
472 }
473 MofDataParser parser(event);
474 return (parser.ReadString(&name_) &&
475 parser.ReadVoidPointer(&id_) &&
476 parser.ReadString(&extra_) &&
477 (parser.empty() ||
478 parser.ReadDWORD(&stack_depth_) &&
479 parser.ReadVoidPointerArray(stack_depth_, &backtrace_) &&
480 parser.empty()));
481 }
482
483 void LogDumper::TraceEventData::WriteContext(std::ostream& out) {
484 }
485
486 bool LogDumper::TraceEventData::WriteLevel(uint8 level, std::ostream& out) {
487 out << type_;
488 return true;
489 }
490
491 void LogDumper::TraceEventData::WriteData(std::ostream& out) {
492 out << name_ << " " << extra_;
493 }
494
495 // LogDumper::LogfileHeaderData implementation
496
497 LogDumper::LogfileHeaderData::LogfileHeaderData()
498 : header_() {
499 }
500
501 LogDumper::LogfileHeaderData::~LogfileHeaderData() {
502 }
503
504 bool LogDumper::LogfileHeaderData::Initialize(EVENT_TRACE* event) {
505 MofDataParser parser(event);
506 return parser.ReadStructure(&header_);
507 }
508
509 void LogDumper::LogfileHeaderData::WriteContext(std::ostream& out) {
510 }
511
512 bool LogDumper::LogfileHeaderData::WriteLevel(uint8 level, std::ostream& out) {
513 return false;
514 }
515
516 void LogDumper::LogfileHeaderData::WriteData(std::ostream& out) {
517 out << "Log captured from Windows "
518 << static_cast<int>(header_->VersionDetail.MajorVersion) << '.'
519 << static_cast<int>(header_->VersionDetail.MinorVersion) << '.'
520 << static_cast<int>(header_->VersionDetail.SubVersion) << '.'
521 << static_cast<int>(header_->VersionDetail.SubMinorVersion)
522 << ". " << header_->EventsLost << " events lost, "
523 << header_->BuffersLost << " buffers lost.";
524 }
525
526 // LogDumper implementation
527
528 // static
529 LogDumper* LogDumper::instance_ = NULL;
530
531 LogDumper::LogDumper(std::ostream& out) : out_(&out) {
532 CHECK(instance_ == NULL);
533 instance_ = this;
534 }
535
536 LogDumper::~LogDumper() {
537 CHECK_EQ(instance_, this);
538 instance_ = NULL;
539 }
540
541 // static
542 LogDumper::MofDataFactoryFn LogDumper::GetMofDataFactory(
543 const GUID& event_class,
544 uint8 type) {
robertshield 2012/03/05 19:20:54 IMO this is needlessly complicated. Returning a fa
grt (UTC plus 2) 2012/03/06 03:24:57 No, I agree wholeheartedly. This was left behind
545 if (IsEqualGUID(event_class, logging::kLogEventId)) {
546 if (type == logging::LOG_MESSAGE)
547 return &CreateMofData<LogMessageData>;
548 else if (type == logging::LOG_MESSAGE_FULL)
549 return &CreateMofData<LogMessageFullData>;
550 } else if (IsEqualGUID(event_class, base::debug::kTraceEventClass32)) {
551 return &CreateMofData<TraceEventData>;
552 } else if (IsEqualGUID(event_class, EventTraceGuid)) {
553 return &CreateMofData<LogfileHeaderData>;
554 }
555 return NULL;
556 }
557
558 // static
559 void LogDumper::ProcessEvent(EVENT_TRACE* event) {
560 if (instance_ != NULL)
561 instance_->DumpEvent(event);
562 }
563
564 void LogDumper::DumpEvent(EVENT_TRACE* event) {
565 scoped_ptr<MofData> payload;
566 MofDataFactoryFn factory_fn = GetMofDataFactory(event->Header.Guid,
567 event->Header.Class.Type);
568
569 if (factory_fn) {
570 payload.reset((*factory_fn)());
571 if (!payload->Initialize(event))
572 payload.reset();
573 }
574
575 *out_ << '[' << event->Header.ProcessId << ':'
576 << event->Header.ThreadId << ':';
577 WriteTimeStamp(event->Header.TimeStamp, *out_);
578 *out_ << ':';
579 if (!payload.get() || !payload->WriteLevel(event->Header.Class.Level, *out_))
580 *out_ << "level" << static_cast<int>(event->Header.Class.Level);
581 if (payload.get()) {
582 *out_ << ':';
583 payload->WriteContext(*out_);
584 }
585 *out_ << "] ";
586 if (payload.get()) {
587 payload->WriteData(*out_);
588 } else {
589 wchar_t guid[64];
590 StringFromGUID2(event->Header.Guid, &guid[0], arraysize(guid));
591 if (factory_fn)
592 *out_ << "parse error";
593 else
594 *out_ << "unsupported event";
595 *out_ << " (class=" << guid << ", type="
596 << static_cast<int>(event->Header.Class.Type) << ")";
597 }
598
599 *out_ << std::endl;
600 }
601
602 void LogDumper::Consume(const FilePath& log_file) {
603 TraceConsumer<&ProcessEvent> consumer;
604 HRESULT hr = S_OK;
605
606 hr = consumer.OpenFileSession(log_file.value().c_str());
607 if (FAILED(hr)) {
608 LOG(ERROR) << "Failed to open session for log file " << log_file.value()
609 << "; hr=" << std::hex << hr;
610 } else {
611 consumer.Consume();
612 consumer.Close();
613 out_->flush();
614 }
615 }
616
617 // static
618 void LogDumper::DumpLog(const FilePath& log_file, std::ostream& out) {
619 LogDumper(out).Consume(log_file);
620 }
621
622 } // namespace
623
624 FileLogger::FileLogger()
625 : event_provider_mask_(),
626 added_chrome_etw_variable_() {
627 }
628
629 FileLogger::~FileLogger() {
630 if (event_provider_mask_) {
631 LOG(WARNING)
632 << __FUNCTION__ << " don't forget to call FileLogger::Uninitialize()";
633 Uninitialize();
634 }
635 }
636
637 void FileLogger::ConfigureChromeEtwLogging() {
638 const string16 chrome_etw_logging(ASCIIToWide(env_vars::kEtwLogging));
639
640 // Set the value in this process and its children.
641 ::SetEnvironmentVariable(chrome_etw_logging.c_str(), L"1");
642
643 // Set the value for the whole system and ask everyone to refresh.
644 base::win::RegKey environment;
645 LONG result = environment.Open(kEnvironmentRoot, kEnvironmentKey,
646 KEY_QUERY_VALUE | KEY_SET_VALUE);
647 if (result == ERROR_SUCCESS) {
648 string16 value;
649 // The actual value of the variable is insignificant in the eyes of Chrome.
650 if (environment.ReadValue(chrome_etw_logging.c_str(),
651 &value) != ERROR_SUCCESS &&
652 environment.WriteValue(chrome_etw_logging.c_str(),
653 L"1") == ERROR_SUCCESS) {
654 environment.Close();
655 added_chrome_etw_variable_ = true;
656 // Announce to the system that a change has been made so that the shell
657 // and other Windowsy bits pick it up; see
658 // http://msdn.microsoft.com/en-us/library/windows/desktop/ms682653.aspx.
659 SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
660 reinterpret_cast<LPARAM>(kEnvironment),
661 SMTO_ABORTIFHUNG,
662 kBroadcastTimeoutMilliseconds, NULL);
663 }
664 } else {
665 SetLastError(result);
666 PLOG(ERROR) << "Failed to open HKLM to check/modify the system environment";
667 }
668 }
669
670 void FileLogger::RevertChromeEtwLogging() {
671 if (added_chrome_etw_variable_) {
672 base::win::RegKey environment;
673 if (environment.Open(kEnvironmentRoot, kEnvironmentKey,
674 KEY_SET_VALUE) == ERROR_SUCCESS) {
675 environment.DeleteValue(ASCIIToWide(env_vars::kEtwLogging).c_str());
676 environment.Close();
677 SendMessageTimeout(HWND_BROADCAST, WM_SETTINGCHANGE, 0,
678 reinterpret_cast<LPARAM>(kEnvironment),
679 SMTO_ABORTIFHUNG,
680 kBroadcastTimeoutMilliseconds, NULL);
681 }
682 added_chrome_etw_variable_ = false;
683 }
684 }
685
686 bool FileLogger::EnableProviders() {
687 bool result = true;
688
689 // Generate ETW log events for this test binary. Log messages at and above
690 // logging::GetMinLogLevel() will continue to go to stderr as well. This
691 // leads to double logging in case of test failures: each LOG statement at
692 // or above the min level will go to stderr during test execution, and then
693 // all events logged to the file session will be dumped again. If this
694 // turns out to be an issue, one could call logging::SetMinLogLevel(INT_MAX)
695 // here (stashing away the previous min log level to be restored in
696 // Uninitialize) to suppress stderr logging during test execution. Then those
697 // events in the file that were logged at/above the old min level from the
698 // test binary could be dumped to stderr if there were no failures.
699 if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
700 logging::LogEventProvider::Initialize(kChromeTestsProvider);
701
702 HRESULT hr = S_OK;
703 for (size_t i = 0; i < arraysize(kProviders); ++i) {
704 if (event_provider_mask_ & (1 << i)) {
705 hr = controller_.EnableProvider(*kProviders[i].provider_name,
706 kProviders[i].level,
707 kProviders[i].flags);
708 if (FAILED(hr)) {
709 result = false;
710 LOG(ERROR) << "Failed to enable event provider " << i
711 << "; hr=" << std::hex << hr;
712 }
713 }
714 }
715
716 return result;
717 }
718
719 void FileLogger::DisableProviders() {
720 HRESULT hr = S_OK;
721 for (size_t i = 0; i < arraysize(kProviders); ++i) {
722 if (event_provider_mask_ & (1 << i)) {
723 hr = controller_.DisableProvider(*kProviders[i].provider_name);
724 LOG_IF(ERROR, FAILED(hr)) << "Failed to disable event provider "
725 << i << "; hr=" << std::hex << hr;
726 }
727 }
728
729 if (event_provider_mask_ & CHROME_TESTS_LOG_PROVIDER)
730 logging::LogEventProvider::Uninitialize();
731 }
732
733 void FileLogger::Initialize() {
734 Initialize(kAllEventProviders);
735 }
736
737 void FileLogger::Initialize(uint32 event_provider_mask) {
738 DCHECK(event_provider_mask_ == 0 && !added_chrome_etw_variable_);
739 CHECK(!g_is_initialized);
740
741 ConfigureChromeEtwLogging();
742
743 // Stop a previous session that wasn't shut down properly.
744 base::win::EtwTraceProperties ignore;
745 HRESULT hr = base::win::EtwTraceController::Stop(kChromeTestSession,
746 &ignore);
747 LOG_IF(ERROR, FAILED(hr) &&
748 hr != HRESULT_FROM_WIN32(ERROR_WMI_INSTANCE_NOT_FOUND))
749 << "Failed to stop a previous trace session; hr=" << std::hex << hr;
750
751 event_provider_mask_ = event_provider_mask;
752
753 g_is_initialized = true;
754 }
755
756 void FileLogger::Uninitialize() {
757 if (is_logging()) {
758 LOG(ERROR)
759 << __FUNCTION__ << " don't forget to call FileLogger::StopLogging()";
760 StopLogging();
761 }
762
763 event_provider_mask_ = 0;
764
765 RevertChromeEtwLogging();
766
767 g_is_initialized = false;
768 }
769
770 bool FileLogger::StartLogging(const FilePath& log_file) {
771 HRESULT hr =
772 controller_.StartFileSession(kChromeTestSession,
773 log_file.value().c_str(), false);
774 if (SUCCEEDED(hr)) {
775 EnableProviders();
776 } else {
777 if (hr == HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED)) {
778 LOG(WARNING) << "Access denied while trying to start trace session. "
779 "This is expected when not running as an administrator.";
780 } else {
781 LOG(ERROR) << "Failed to start trace session to file " << log_file.value()
782 << "; hr=" << std::hex << hr;
783 }
784 return false;
785 }
786 return true;
787 }
788
789 void FileLogger::StopLogging() {
790 HRESULT hr = S_OK;
791
792 DisableProviders();
793
794 hr = controller_.Flush(NULL);
795 LOG_IF(ERROR, FAILED(hr))
796 << "Failed to flush events; hr=" << std::hex << hr;
797 hr = controller_.Stop(NULL);
798 LOG_IF(ERROR, FAILED(hr))
799 << "Failed to stop ETW session; hr=" << std::hex << hr;
800 }
801
802 // static
803 void FileLogger::DumpLogFile(const FilePath& log_file, std::ostream& out) {
804 LogDumper::DumpLog(log_file, out);
805 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698