Commit 46d2c0ed authored by fgorski's avatar fgorski Committed by Commit bot

Revert of Update DevTools Tracing.Start to accept trace config as a parameter...

Revert of Update DevTools Tracing.Start to accept trace config as a parameter (patchset #10 id:180001 of https://codereview.chromium.org/1765153002/ )

Reason for revert:
TraceConfigTest.TraceConfigFromDict fialed

https://build.chromium.org/p/chromium.linux/builders/Cast%20Linux/builds/21289/steps/base_unittests/logs/stdio
https://build.chromium.org/p/chromium.linux/builders/Cast%20Linux/builds/21289

Original issue's description:
> Update DevTools Tracing.Start to accept trace config as
> a parameter
>
> This CL updates Tracing.Start to accept trace config as
> a parameter when starting tracing. It is backward compatible
> with the old way.
>
> Design doc: https://goo.gl/GxQ23k
> BUG=579358
>
> Committed: https://crrev.com/c0e3792f832fc454324dbe35d01079b124b072cd
> Cr-Commit-Position: refs/heads/master@{#381783}

TBR=caseq@chromium.org,primiano@chromium.org,nednguyen@google.com,petrcermak@chromium.org,simonhatch@chromium.org,pfeldman@chromium.org,zhenw@chromium.org
# Skipping CQ checks because original CL landed less than 1 days ago.
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=579358

Review URL: https://codereview.chromium.org/1814043002

Cr-Commit-Position: refs/heads/master@{#381794}
parent 7a424887
......@@ -105,10 +105,6 @@ TraceConfig::TraceConfig(const std::string& category_filter_string,
InitializeFromStrings(category_filter_string, trace_options_string);
}
TraceConfig::TraceConfig(const DictionaryValue& config) {
InitializeFromConfigDict(config);
}
TraceConfig::TraceConfig(const std::string& config_string) {
if (!config_string.empty())
InitializeFromConfigString(config_string);
......@@ -292,10 +288,18 @@ void TraceConfig::InitializeDefault() {
excluded_categories_.push_back("*Test");
}
void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
void TraceConfig::InitializeFromConfigString(const std::string& config_string) {
scoped_ptr<base::Value> value(base::JSONReader::Read(config_string));
if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) {
InitializeDefault();
return;
}
scoped_ptr<base::DictionaryValue> dict(
static_cast<base::DictionaryValue*>(value.release()));
record_mode_ = RECORD_UNTIL_FULL;
std::string record_mode;
if (dict.GetString(kRecordModeParam, &record_mode)) {
if (dict->GetString(kRecordModeParam, &record_mode)) {
if (record_mode == kRecordUntilFull) {
record_mode_ = RECORD_UNTIL_FULL;
} else if (record_mode == kRecordContinuously) {
......@@ -308,57 +312,42 @@ void TraceConfig::InitializeFromConfigDict(const DictionaryValue& dict) {
}
bool enable_sampling;
if (!dict.GetBoolean(kEnableSamplingParam, &enable_sampling))
if (!dict->GetBoolean(kEnableSamplingParam, &enable_sampling))
enable_sampling_ = false;
else
enable_sampling_ = enable_sampling;
bool enable_systrace;
if (!dict.GetBoolean(kEnableSystraceParam, &enable_systrace))
if (!dict->GetBoolean(kEnableSystraceParam, &enable_systrace))
enable_systrace_ = false;
else
enable_systrace_ = enable_systrace;
bool enable_argument_filter;
if (!dict.GetBoolean(kEnableArgumentFilterParam, &enable_argument_filter))
if (!dict->GetBoolean(kEnableArgumentFilterParam, &enable_argument_filter))
enable_argument_filter_ = false;
else
enable_argument_filter_ = enable_argument_filter;
const base::ListValue* category_list = nullptr;
if (dict.GetList(kIncludedCategoriesParam, &category_list))
base::ListValue* category_list = nullptr;
if (dict->GetList(kIncludedCategoriesParam, &category_list))
SetCategoriesFromIncludedList(*category_list);
if (dict.GetList(kExcludedCategoriesParam, &category_list))
if (dict->GetList(kExcludedCategoriesParam, &category_list))
SetCategoriesFromExcludedList(*category_list);
if (dict.GetList(kSyntheticDelaysParam, &category_list))
if (dict->GetList(kSyntheticDelaysParam, &category_list))
SetSyntheticDelaysFromList(*category_list);
if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) {
// If dump triggers not set, the client is using the legacy with just
// category enabled. So, use the default periodic dump config.
const base::DictionaryValue* memory_dump_config = nullptr;
if (dict.GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
base::DictionaryValue* memory_dump_config = nullptr;
if (dict->GetDictionary(kMemoryDumpConfigParam, &memory_dump_config))
SetMemoryDumpConfig(*memory_dump_config);
else
SetDefaultMemoryDumpConfig();
}
}
void TraceConfig::InitializeFromConfigString(const std::string& config_string) {
scoped_ptr<Value> value(JSONReader::Read(config_string));
if (!value)
return InitializeDefault();
const DictionaryValue* dict = nullptr;
bool is_dict = value->GetAsDictionary(&dict);
if (!is_dict)
return InitializeDefault();
DCHECK(dict);
InitializeFromConfigDict(*dict);
}
void TraceConfig::InitializeFromStrings(
const std::string& category_filter_string,
const std::string& trace_options_string) {
......
......@@ -130,10 +130,6 @@ class BASE_EXPORT TraceConfig {
// disabled-by-default-memory-infra category is enabled.
explicit TraceConfig(const std::string& config_string);
// Functionally identical to the above, but takes a parsed dictionary as input
// instead of its JSON serialization.
explicit TraceConfig(const DictionaryValue& config);
TraceConfig(const TraceConfig& tc);
~TraceConfig();
......@@ -194,10 +190,7 @@ class BASE_EXPORT TraceConfig {
// in the suffix 'Debug' or 'Test'.
void InitializeDefault();
// Initialize from a config dictionary.
void InitializeFromConfigDict(const DictionaryValue& dict);
// Initialize from a config string.
// Initialize from the config string
void InitializeFromConfigString(const std::string& config_string);
// Initialize from category filter and trace options strings
......
......@@ -4,7 +4,6 @@
#include <stddef.h>
#include "base/json/json_reader.h"
#include "base/macros.h"
#include "base/trace_event/memory_dump_manager.h"
#include "base/trace_event/trace_config.h"
......@@ -24,27 +23,6 @@ const char kDefaultTraceConfigString[] =
"\"excluded_categories\":[\"*Debug\",\"*Test\"],"
"\"record_mode\":\"record-until-full\""
"}";
const char kCustomTraceConfigString[] =
"{"
"\"enable_argument_filter\":true,"
"\"enable_sampling\":true,"
"\"enable_systrace\":true,"
"\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
"\"included_categories\":[\"included\","
"\"inc_pattern*\","
"\"disabled-by-default-cc\","
"\"disabled-by-default-memory-infra\"],"
"\"memory_dump_config\":{"
"\"triggers\":["
"{\"mode\":\"light\",\"periodic_interval_ms\":50},"
"{\"mode\":\"detailed\",\"periodic_interval_ms\":1000}"
"]"
"},"
"\"record_mode\":\"record-continuously\","
"\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
"}";
} // namespace
TEST(TraceConfigTest, TraceConfigFromValidLegacyFormat) {
......@@ -281,47 +259,6 @@ TEST(TraceConfigTest, ConstructDefaultTraceConfig) {
EXPECT_FALSE(tc.IsCategoryGroupEnabled("CategoryDebug,CategoryTest"));
}
TEST(TraceConfigTest, TraceConfigFromDict) {
// Passing in empty dictionary will not result in default trace config.
DictionaryValue dict;
TraceConfig tc(dict);
EXPECT_STRNE(kDefaultTraceConfigString, tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, tc.GetTraceRecordMode());
EXPECT_FALSE(tc.IsSamplingEnabled());
EXPECT_FALSE(tc.IsSystraceEnabled());
EXPECT_FALSE(tc.IsArgumentFilterEnabled());
EXPECT_STREQ("", tc.ToCategoryFilterString().c_str());
scoped_ptr<Value> default_value(JSONReader::Read(kDefaultTraceConfigString));
DCHECK(default_value);
const DictionaryValue* default_dict = nullptr;
bool is_dict = default_value->GetAsDictionary(&default_dict);
DCHECK(is_dict);
TraceConfig default_tc(*default_dict);
EXPECT_STREQ(kDefaultTraceConfigString, default_tc.ToString().c_str());
EXPECT_EQ(RECORD_UNTIL_FULL, default_tc.GetTraceRecordMode());
EXPECT_FALSE(default_tc.IsSamplingEnabled());
EXPECT_FALSE(default_tc.IsSystraceEnabled());
EXPECT_FALSE(default_tc.IsArgumentFilterEnabled());
EXPECT_STREQ("-*Debug,-*Test", default_tc.ToCategoryFilterString().c_str());
scoped_ptr<Value> custom_value(JSONReader::Read(kCustomTraceConfigString));
DCHECK(custom_value);
const DictionaryValue* custom_dict = nullptr;
DCHECK(custom_value->GetAsDictionary(&custom_dict));
TraceConfig custom_tc(*custom_dict);
EXPECT_STREQ(kCustomTraceConfigString, custom_tc.ToString().c_str());
EXPECT_EQ(RECORD_CONTINUOUSLY, custom_tc.GetTraceRecordMode());
EXPECT_TRUE(custom_tc.IsSamplingEnabled());
EXPECT_TRUE(custom_tc.IsSystraceEnabled());
EXPECT_TRUE(custom_tc.IsArgumentFilterEnabled());
EXPECT_STREQ("included,inc_pattern*,"
"disabled-by-default-cc,disabled-by-default-memory-infra,"
"-excluded,-exc_pattern*,"
"DELAY(test.Delay1;16),DELAY(test.Delay2;32)",
custom_tc.ToCategoryFilterString().c_str());
}
TEST(TraceConfigTest, TraceConfigFromValidString) {
// Using some non-empty config string.
const char config_string[] =
......
......@@ -11,6 +11,7 @@
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/values.h"
......@@ -107,7 +108,9 @@ bool TraceConfigFile::ParseTraceConfigFileContent(const std::string& content) {
if (!dict->GetDictionary(kTraceConfigParam, &trace_config_dict))
return false;
trace_config_ = base::trace_event::TraceConfig(*trace_config_dict);
std::string trace_config_str;
base::JSONWriter::Write(*trace_config_dict, &trace_config_str);
trace_config_ = base::trace_event::TraceConfig(trace_config_str);
if (!dict->GetInteger(kStartupDurationParam, &startup_duration_))
startup_duration_ = 0;
......
......@@ -8,7 +8,6 @@
#include "base/bind.h"
#include "base/format_macros.h"
#include "base/json/json_writer.h"
#include "base/memory/ref_counted_memory.h"
#include "base/strings/string_split.h"
#include "base/strings/stringprintf.h"
......@@ -31,46 +30,6 @@ namespace {
const double kMinimumReportingInterval = 250.0;
const char kRecordModeParam[] = "record_mode";
// Convert from camel case to separator + lowercase.
std::string ConvertFromCamelCase(const std::string& in_str, char separator) {
std::string out_str;
out_str.reserve(in_str.size());
for (const char& c : in_str) {
if (isupper(c)) {
out_str.push_back(separator);
out_str.push_back(tolower(c));
} else {
out_str.push_back(c);
}
}
return out_str;
}
scoped_ptr<base::Value> ConvertDictKeyStyle(const base::Value& value) {
const base::DictionaryValue* dict = nullptr;
if (value.GetAsDictionary(&dict)) {
scoped_ptr<base::DictionaryValue> out_dict(new base::DictionaryValue());
for (base::DictionaryValue::Iterator it(*dict); !it.IsAtEnd();
it.Advance()) {
out_dict->Set(ConvertFromCamelCase(it.key(), '_'),
ConvertDictKeyStyle(it.value()));
}
return std::move(out_dict);
}
const base::ListValue* list = nullptr;
if (value.GetAsList(&list)) {
scoped_ptr<base::ListValue> out_list(new base::ListValue());
for (const auto& value : *list)
out_list->Append(ConvertDictKeyStyle(*value));
return std::move(out_list);
}
return value.CreateDeepCopy();
}
class DevToolsTraceSinkProxy : public TracingController::TraceDataSink {
public:
explicit DevToolsTraceSinkProxy(base::WeakPtr<TracingHandler> handler)
......@@ -171,37 +130,23 @@ void TracingHandler::OnTraceToStreamComplete(const std::string& stream_handle) {
TracingCompleteParams::Create()->set_stream(stream_handle));
}
Response TracingHandler::Start(
DevToolsCommandId command_id,
const std::string* categories,
const std::string* options,
const double* buffer_usage_reporting_interval,
const std::string* transfer_mode,
const scoped_ptr<base::DictionaryValue>& config) {
Response TracingHandler::Start(DevToolsCommandId command_id,
const std::string* categories,
const std::string* options,
const double* buffer_usage_reporting_interval,
const std::string* transfer_mode) {
if (IsTracing())
return Response::InternalError("Tracing is already started");
if (config && (categories || options)) {
return Response::InternalError(
"Either trace config (preferred), or categories+options should be "
"specified, but not both.");
}
did_initiate_recording_ = true;
return_as_stream_ =
transfer_mode && *transfer_mode == start::kTransferModeReturnAsStream;
base::trace_event::TraceConfig trace_config(
categories ? *categories : std::string(),
options ? *options : std::string());
if (buffer_usage_reporting_interval)
SetupTimer(*buffer_usage_reporting_interval);
base::trace_event::TraceConfig trace_config;
if (config) {
trace_config = GetTraceConfigFromDevToolsConfig(*config);
} else if (categories || options) {
trace_config = base::trace_event::TraceConfig(
categories ? *categories : std::string(),
options ? *options : std::string());
}
// If inspected target is a render process Tracing.start will be handled by
// tracing agent in the renderer.
TracingController::GetInstance()->StartTracing(
......@@ -336,21 +281,6 @@ bool TracingHandler::IsStartupTracingActive() {
TracingController::GetInstance()->IsTracing();
}
// static
base::trace_event::TraceConfig TracingHandler::GetTraceConfigFromDevToolsConfig(
const base::DictionaryValue& devtools_config) {
scoped_ptr<base::Value> value = ConvertDictKeyStyle(devtools_config);
DCHECK(value && value->IsType(base::Value::TYPE_DICTIONARY));
scoped_ptr<base::DictionaryValue> tracing_dict(
static_cast<base::DictionaryValue*>(value.release()));
std::string mode;
if (tracing_dict->GetString(kRecordModeParam, &mode))
tracing_dict->SetString(kRecordModeParam, ConvertFromCamelCase(mode, '-'));
return base::trace_event::TraceConfig(*tracing_dict);
}
} // namespace tracing
} // namespace devtools
} // namespace content
......@@ -11,12 +11,10 @@
#include <set>
#include <string>
#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/trace_event/trace_event.h"
#include "content/browser/devtools/protocol/devtools_protocol_dispatcher.h"
#include "content/common/content_export.h"
#include "content/public/browser/tracing_controller.h"
namespace base {
......@@ -53,8 +51,7 @@ class TracingHandler {
const std::string* categories,
const std::string* options,
const double* buffer_usage_reporting_interval,
const std::string* transfer_mode,
const scoped_ptr<base::DictionaryValue>& config);
const std::string* transfer_mode);
Response End(DevToolsCommandId command_id);
Response GetCategories(DevToolsCommandId command);
Response RequestMemoryDump(DevToolsCommandId command_id);
......@@ -76,9 +73,6 @@ class TracingHandler {
const scoped_refptr<TracingController::TraceDataSink>& trace_data_sink);
bool IsTracing() const;
static bool IsStartupTracingActive();
CONTENT_EXPORT static base::trace_event::TraceConfig
GetTraceConfigFromDevToolsConfig(
const base::DictionaryValue& devtools_config);
scoped_ptr<base::Timer> buffer_usage_poll_timer_;
Target target_;
......@@ -90,8 +84,6 @@ class TracingHandler {
bool return_as_stream_;
base::WeakPtrFactory<TracingHandler> weak_factory_;
FRIEND_TEST_ALL_PREFIXES(TracingHandlerTest,
GetTraceConfigFromDevToolsConfig);
DISALLOW_COPY_AND_ASSIGN(TracingHandler);
};
......
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/json/json_reader.h"
#include "base/trace_event/trace_config.h"
#include "base/values.h"
#include "content/browser/devtools/protocol/tracing_handler.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
namespace devtools {
namespace tracing {
namespace {
const char kCustomTraceConfigString[] =
"{"
"\"enable_argument_filter\":true,"
"\"enable_sampling\":true,"
"\"enable_systrace\":true,"
"\"excluded_categories\":[\"excluded\",\"exc_pattern*\"],"
"\"included_categories\":[\"included\","
"\"inc_pattern*\","
"\"disabled-by-default-cc\","
"\"disabled-by-default-memory-infra\"],"
"\"memory_dump_config\":{"
"\"triggers\":["
"{\"mode\":\"light\",\"periodic_interval_ms\":50},"
"{\"mode\":\"detailed\",\"periodic_interval_ms\":1000}"
"]"
"},"
"\"record_mode\":\"record-continuously\","
"\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
"}";
const char kCustomTraceConfigStringDevToolsStyle[] =
"{"
"\"enableArgumentFilter\":true,"
"\"enableSampling\":true,"
"\"enableSystrace\":true,"
"\"excludedCategories\":[\"excluded\",\"exc_pattern*\"],"
"\"includedCategories\":[\"included\","
"\"inc_pattern*\","
"\"disabled-by-default-cc\","
"\"disabled-by-default-memory-infra\"],"
"\"memoryDumpConfig\":{"
"\"triggers\":["
"{\"mode\":\"light\",\"periodicIntervalMs\":50},"
"{\"mode\":\"detailed\",\"periodicIntervalMs\":1000}"
"]"
"},"
"\"recordMode\":\"recordContinuously\","
"\"synthetic_delays\":[\"test.Delay1;16\",\"test.Delay2;32\"]"
"}";
}
TEST(TracingHandlerTest, GetTraceConfigFromDevToolsConfig) {
scoped_ptr<base::Value> value = base::JSONReader::Read(
kCustomTraceConfigStringDevToolsStyle);
scoped_ptr<base::DictionaryValue> devtools_style_dict(
static_cast<base::DictionaryValue*>(value.release()));
base::trace_event::TraceConfig trace_config =
TracingHandler::GetTraceConfigFromDevToolsConfig(*devtools_style_dict);
EXPECT_STREQ(kCustomTraceConfigString, trace_config.ToString().c_str());
}
} // namespace tracing
} // namespace devtools
} // namespace content
......@@ -392,7 +392,6 @@
'browser/device_sensors/sensor_manager_android_unittest.cc',
'browser/device_sensors/sensor_manager_chromeos_unittest.cc',
'browser/devtools/devtools_manager_unittest.cc',
'browser/devtools/protocol/tracing_handler_unittest.cc',
'browser/devtools/shared_worker_devtools_manager_unittest.cc',
'browser/dom_storage/dom_storage_area_unittest.cc',
'browser/dom_storage/dom_storage_context_impl_unittest.cc',
......
......@@ -43,21 +43,14 @@ void InspectorTracingAgent::restore()
{
emitMetadataEvents();
}
void InspectorTracingAgent::start(ErrorString* errorString,
void InspectorTracingAgent::start(ErrorString*,
const Maybe<String>& categories,
const Maybe<String>& options,
const Maybe<double>& bufferUsageReportingInterval,
const Maybe<String>& transferMode,
const Maybe<protocol::Tracing::TraceConfig>& config,
PassOwnPtr<StartCallback> callback)
{
ASSERT(sessionId().isEmpty());
if (config.isJust()) {
*errorString =
"Using trace config on renderer targets is not supported yet.";
return;
}
m_state->setString(TracingAgentState::sessionId, IdentifiersFactory::createIdentifier());
m_client->enableTracing(categories.fromMaybe(String()));
emitMetadataEvents();
......
......@@ -42,7 +42,7 @@ public:
void disable(ErrorString*) override;
// Protocol method implementations.
void start(ErrorString*, const Maybe<String>& categories, const Maybe<String>& options, const Maybe<double>& bufferUsageReportingInterval, const Maybe<String>& transferMode, const Maybe<protocol::Tracing::TraceConfig>&, PassOwnPtr<StartCallback>) override;
void start(ErrorString*, const Maybe<String>& categories, const Maybe<String>& options, const Maybe<double>& bufferUsageReportingInterval, const Maybe<String>& transferMode, PassOwnPtr<StartCallback>) override;
void end(ErrorString*, PassOwnPtr<EndCallback>) override;
// Methods for other agents to use.
......
......@@ -4796,50 +4796,16 @@
},
{
"domain": "Tracing",
"types": [
{
"id": "MemoryDumpTrigger",
"type": "object",
"properties": [
{ "name": "mode", "type": "string", "enum": ["light", "detailed"], "description": "Level of detail of the triggered memory dumps." },
{ "name": "periodicIntervalMs", "type": "integer", "description": "Length of the periodic intervals between the triggered memory dumps." }
],
"description": "Memory dump trigger configuration."
},
{
"id": "MemoryDumpConfig",
"type": "object",
"properties": [
{ "name": "triggers", "type": "array", "items": { "$ref": "MemoryDumpTrigger" }, "optional": false, "description": "Memory dump trigger configuration." }
],
"description": "Configuration for memory dump triggers. Used only when \"memory-infra\" category is enabled."
},
{
"id": "TraceConfig",
"type": "object",
"properties": [
{ "name": "recordMode", "type": "string", "optional": true, "enum": ["recordUntilFull", "recordContinuously", "recordAsMuchAsPossible", "echoToConsole"], "description": "Controls how the trace buffer stores data." },
{ "name": "enableSampling", "type": "boolean", "optional": true, "description": "Turns on JavaScript stack sampling." },
{ "name": "enableSystrace", "type": "boolean", "optional": true, "description": "Turns on system tracing." },
{ "name": "enableArgumentFilter", "type": "boolean", "optional": true, "description": "Turns on argument filter." },
{ "name": "includedCategories", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Included category filters." },
{ "name": "excludedCategories", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Excluded category filters." },
{ "name": "syntheticDelays", "type": "array", "items": { "type": "string" }, "optional": true, "description": "Configuration to synthesize the delays in tracing." },
{ "name": "memoryDumpConfig", "$ref": "MemoryDumpConfig", "optional": true, "description": "Configuration for memory dump triggers. Used only when \"memory-infra\" category is enabled." }
]
}
],
"commands": [
{
"name": "start",
"async": true,
"description": "Start trace events collection.",
"parameters": [
{ "name": "categories", "type": "string", "optional": true, "deprecated": true, "description": "Category/tag filter" },
{ "name": "options", "type": "string", "optional": true, "deprecated": true, "description": "Tracing options" },
{ "name": "categories", "type": "string", "optional": true, "description": "Category/tag filter" },
{ "name": "options", "type": "string", "optional": true, "description": "Tracing options" },
{ "name": "bufferUsageReportingInterval", "type": "number", "optional": true, "description": "If set, the agent will issue bufferUsage events at this interval, specified in milliseconds" },
{ "name": "transferMode", "type": "string", "enum": ["ReportEvents", "ReturnAsStream"], "optional": true, "description": "Whether to report trace events as series of dataCollected events or to save trace to a stream (defaults to <code>ReportEvents</code>)." },
{ "name": "traceConfig", "$ref": "TraceConfig", "optional": true, "description": "" }
{ "name": "transferMode", "type": "string", "enum": ["ReportEvents", "ReturnAsStream"], "optional": true, "description": "Whether to report trace events as series of dataCollected events or to save trace to a stream (defaults to <code>ReportEvents</code>)." }
],
"handlers": ["browser", "renderer"]
},
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment