| // Copyright 2014 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/test/trace_to_file.h" |
| |
| #include "base/base_switches.h" |
| #include "base/command_line.h" |
| #include "base/files/file_util.h" |
| #include "base/functional/bind.h" |
| #include "base/memory/ref_counted_memory.h" |
| #include "base/run_loop.h" |
| #include "base/task/single_thread_task_runner.h" |
| #include "base/test/task_environment.h" |
| #include "base/trace_event/trace_buffer.h" |
| #include "base/trace_event/trace_log.h" |
| |
| namespace base { |
| namespace test { |
| |
| TraceToFile::TraceToFile() : started_(false) { |
| } |
| |
| TraceToFile::~TraceToFile() { |
| EndTracingIfNeeded(); |
| } |
| |
| void TraceToFile::BeginTracingFromCommandLineOptions() { |
| DCHECK(CommandLine::InitializedForCurrentProcess()); |
| DCHECK(!started_); |
| |
| if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFile)) |
| return; |
| |
| // Empty filter (i.e. just --trace-to-file) turns into default categories in |
| // TraceEventImpl |
| std::string filter = CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| switches::kTraceToFile); |
| |
| FilePath path; |
| if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kTraceToFileName)) { |
| path = FilePath(CommandLine::ForCurrentProcess() |
| ->GetSwitchValuePath(switches::kTraceToFileName)); |
| } else { |
| path = FilePath(FILE_PATH_LITERAL("trace.json")); |
| } |
| |
| BeginTracing(path, filter); |
| } |
| |
| void TraceToFile::BeginTracing(const FilePath& path, |
| const std::string& categories) { |
| DCHECK(!started_); |
| started_ = true; |
| path_ = path; |
| WriteFileHeader(); |
| |
| trace_event::TraceLog::GetInstance()->SetEnabled( |
| trace_event::TraceConfig(categories, trace_event::RECORD_UNTIL_FULL), |
| trace_event::TraceLog::RECORDING_MODE); |
| } |
| |
| void TraceToFile::WriteFileHeader() { |
| WriteFile(path_, "{\"traceEvents\": ["); |
| } |
| |
| void TraceToFile::AppendFileFooter() { |
| const char str[] = "]}"; |
| AppendToFile(path_, str); |
| } |
| |
| void TraceToFile::TraceOutputCallback(const std::string& data) { |
| bool ret = AppendToFile(path_, data); |
| DCHECK(ret); |
| } |
| |
| static void OnTraceDataCollected( |
| OnceClosure quit_closure, |
| trace_event::TraceResultBuffer* buffer, |
| const scoped_refptr<RefCountedString>& json_events_str, |
| bool has_more_events) { |
| buffer->AddFragment(json_events_str->data()); |
| if (!has_more_events) |
| std::move(quit_closure).Run(); |
| } |
| |
| void TraceToFile::EndTracingIfNeeded() { |
| if (!started_) |
| return; |
| started_ = false; |
| |
| trace_event::TraceLog::GetInstance()->SetDisabled(); |
| |
| trace_event::TraceResultBuffer buffer; |
| buffer.SetOutputCallback( |
| BindRepeating(&TraceToFile::TraceOutputCallback, Unretained(this))); |
| |
| // In tests we might not have a TaskEnvironment, create one if needed. |
| std::unique_ptr<SingleThreadTaskEnvironment> task_environment; |
| if (!SingleThreadTaskRunner::HasCurrentDefault()) |
| task_environment = std::make_unique<SingleThreadTaskEnvironment>(); |
| |
| RunLoop run_loop; |
| trace_event::TraceLog::GetInstance()->Flush(BindRepeating( |
| &OnTraceDataCollected, run_loop.QuitClosure(), Unretained(&buffer))); |
| run_loop.Run(); |
| |
| AppendFileFooter(); |
| } |
| |
| } // namespace test |
| } // namespace base |