1 // Copyright (c) 2014 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 "base/test/trace_to_file.h"
6
7 #include "base/base_switches.h"
8 #include "base/bind.h"
9 #include "base/command_line.h"
10 #include "base/files/file_util.h"
11 #include "base/memory/ref_counted_memory.h"
12 #include "base/run_loop.h"
13 #include "base/trace_event/trace_buffer.h"
14 #include "base/trace_event/trace_log.h"
15
16 namespace base {
17 namespace test {
18
TraceToFile()19 TraceToFile::TraceToFile() : started_(false) {
20 }
21
~TraceToFile()22 TraceToFile::~TraceToFile() {
23 EndTracingIfNeeded();
24 }
25
BeginTracingFromCommandLineOptions()26 void TraceToFile::BeginTracingFromCommandLineOptions() {
27 DCHECK(CommandLine::InitializedForCurrentProcess());
28 DCHECK(!started_);
29
30 if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFile))
31 return;
32
33 // Empty filter (i.e. just --trace-to-file) turns into default categories in
34 // TraceEventImpl
35 std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
36 switches::kTraceToFile);
37
38 FilePath path;
39 if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFileName)) {
40 path = FilePath(CommandLine::ForCurrentProcess()
41 ->GetSwitchValuePath(switches::kTraceToFileName));
42 } else {
43 path = FilePath(FILE_PATH_LITERAL("trace.json"));
44 }
45
46 BeginTracing(path, filter);
47 }
48
BeginTracing(const FilePath & path,const std::string & categories)49 void TraceToFile::BeginTracing(const FilePath& path,
50 const std::string& categories) {
51 DCHECK(!started_);
52 started_ = true;
53 path_ = path;
54 WriteFileHeader();
55
56 trace_event::TraceLog::GetInstance()->SetEnabled(
57 trace_event::TraceConfig(categories, trace_event::RECORD_UNTIL_FULL),
58 trace_event::TraceLog::RECORDING_MODE);
59 }
60
WriteFileHeader()61 void TraceToFile::WriteFileHeader() {
62 const char str[] = "{\"traceEvents\": [";
63 WriteFile(path_, str, static_cast<int>(strlen(str)));
64 }
65
AppendFileFooter()66 void TraceToFile::AppendFileFooter() {
67 const char str[] = "]}";
68 AppendToFile(path_, str, static_cast<int>(strlen(str)));
69 }
70
TraceOutputCallback(const std::string & data)71 void TraceToFile::TraceOutputCallback(const std::string& data) {
72 bool ret = AppendToFile(path_, data.c_str(), static_cast<int>(data.size()));
73 DCHECK(ret);
74 }
75
OnTraceDataCollected(Closure quit_closure,trace_event::TraceResultBuffer * buffer,const scoped_refptr<RefCountedString> & json_events_str,bool has_more_events)76 static void OnTraceDataCollected(
77 Closure quit_closure,
78 trace_event::TraceResultBuffer* buffer,
79 const scoped_refptr<RefCountedString>& json_events_str,
80 bool has_more_events) {
81 buffer->AddFragment(json_events_str->data());
82 if (!has_more_events)
83 quit_closure.Run();
84 }
85
EndTracingIfNeeded()86 void TraceToFile::EndTracingIfNeeded() {
87 if (!started_)
88 return;
89 started_ = false;
90
91 trace_event::TraceLog::GetInstance()->SetDisabled();
92
93 trace_event::TraceResultBuffer buffer;
94 buffer.SetOutputCallback(
95 Bind(&TraceToFile::TraceOutputCallback, Unretained(this)));
96
97 RunLoop run_loop;
98 trace_event::TraceLog::GetInstance()->Flush(
99 Bind(&OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer)));
100 run_loop.Run();
101
102 AppendFileFooter();
103 }
104
105 } // namespace test
106 } // namespace base
107