1 // Copyright (c) 2015 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/trace_event/trace_config.h" 6 7 #include <stddef.h> 8 9 #include <utility> 10 11 #include "base/json/json_reader.h" 12 #include "base/json/json_writer.h" 13 #include "base/strings/pattern.h" 14 #include "base/strings/string_split.h" 15 #include "base/strings/string_tokenizer.h" 16 #include "base/strings/stringprintf.h" 17 #include "base/trace_event/memory_dump_manager.h" 18 #include "base/trace_event/memory_dump_request_args.h" 19 #include "base/trace_event/trace_event.h" 20 21 namespace base { 22 namespace trace_event { 23 24 namespace { 25 26 // String options that can be used to initialize TraceOptions. 27 const char kRecordUntilFull[] = "record-until-full"; 28 const char kRecordContinuously[] = "record-continuously"; 29 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible"; 30 const char kTraceToConsole[] = "trace-to-console"; 31 const char kEnableSampling[] = "enable-sampling"; 32 const char kEnableSystrace[] = "enable-systrace"; 33 const char kEnableArgumentFilter[] = "enable-argument-filter"; 34 35 // String parameters that can be used to parse the trace config string. 36 const char kRecordModeParam[] = "record_mode"; 37 const char kEnableSamplingParam[] = "enable_sampling"; 38 const char kEnableSystraceParam[] = "enable_systrace"; 39 const char kEnableArgumentFilterParam[] = "enable_argument_filter"; 40 const char kIncludedCategoriesParam[] = "included_categories"; 41 const char kExcludedCategoriesParam[] = "excluded_categories"; 42 const char kSyntheticDelaysParam[] = "synthetic_delays"; 43 44 const char kSyntheticDelayCategoryFilterPrefix[] = "DELAY("; 45 46 // String parameters that is used to parse memory dump config in trace config 47 // string. 48 const char kMemoryDumpConfigParam[] = "memory_dump_config"; 49 const char kTriggersParam[] = "triggers"; 50 const char kPeriodicIntervalParam[] = "periodic_interval_ms"; 51 const char kModeParam[] = "mode"; 52 53 // Default configuration of memory dumps. 54 const TraceConfig::MemoryDumpTriggerConfig kDefaultHeavyMemoryDumpTrigger = { 55 2000, // periodic_interval_ms 56 MemoryDumpLevelOfDetail::DETAILED}; 57 const TraceConfig::MemoryDumpTriggerConfig kDefaultLightMemoryDumpTrigger = { 58 250, // periodic_interval_ms 59 MemoryDumpLevelOfDetail::LIGHT}; 60 61 class ConvertableTraceConfigToTraceFormat 62 : public base::trace_event::ConvertableToTraceFormat { 63 public: 64 explicit ConvertableTraceConfigToTraceFormat(const TraceConfig& trace_config) 65 : trace_config_(trace_config) {} 66 void AppendAsTraceFormat(std::string* out) const override { 67 out->append(trace_config_.ToString()); 68 } 69 70 protected: 71 ~ConvertableTraceConfigToTraceFormat() override {} 72 73 private: 74 const TraceConfig trace_config_; 75 }; 76 77 } // namespace 78 79 TraceConfig::TraceConfig() { 80 InitializeDefault(); 81 } 82 83 TraceConfig::TraceConfig(const std::string& category_filter_string, 84 const std::string& trace_options_string) { 85 InitializeFromStrings(category_filter_string, trace_options_string); 86 } 87 88 TraceConfig::TraceConfig(const std::string& category_filter_string, 89 TraceRecordMode record_mode) { 90 std::string trace_options_string; 91 switch (record_mode) { 92 case RECORD_UNTIL_FULL: 93 trace_options_string = kRecordUntilFull; 94 break; 95 case RECORD_CONTINUOUSLY: 96 trace_options_string = kRecordContinuously; 97 break; 98 case RECORD_AS_MUCH_AS_POSSIBLE: 99 trace_options_string = kRecordAsMuchAsPossible; 100 break; 101 case ECHO_TO_CONSOLE: 102 trace_options_string = kTraceToConsole; 103 break; 104 default: 105 NOTREACHED(); 106 } 107 InitializeFromStrings(category_filter_string, trace_options_string); 108 } 109 110 TraceConfig::TraceConfig(const std::string& config_string) { 111 if (!config_string.empty()) 112 InitializeFromConfigString(config_string); 113 else 114 InitializeDefault(); 115 } 116 117 TraceConfig::TraceConfig(const TraceConfig& tc) 118 : record_mode_(tc.record_mode_), 119 enable_sampling_(tc.enable_sampling_), 120 enable_systrace_(tc.enable_systrace_), 121 enable_argument_filter_(tc.enable_argument_filter_), 122 memory_dump_config_(tc.memory_dump_config_), 123 included_categories_(tc.included_categories_), 124 disabled_categories_(tc.disabled_categories_), 125 excluded_categories_(tc.excluded_categories_), 126 synthetic_delays_(tc.synthetic_delays_) {} 127 128 TraceConfig::~TraceConfig() { 129 } 130 131 TraceConfig& TraceConfig::operator=(const TraceConfig& rhs) { 132 if (this == &rhs) 133 return *this; 134 135 record_mode_ = rhs.record_mode_; 136 enable_sampling_ = rhs.enable_sampling_; 137 enable_systrace_ = rhs.enable_systrace_; 138 enable_argument_filter_ = rhs.enable_argument_filter_; 139 memory_dump_config_ = rhs.memory_dump_config_; 140 included_categories_ = rhs.included_categories_; 141 disabled_categories_ = rhs.disabled_categories_; 142 excluded_categories_ = rhs.excluded_categories_; 143 synthetic_delays_ = rhs.synthetic_delays_; 144 return *this; 145 } 146 147 const TraceConfig::StringList& TraceConfig::GetSyntheticDelayValues() const { 148 return synthetic_delays_; 149 } 150 151 std::string TraceConfig::ToString() const { 152 base::DictionaryValue dict; 153 ToDict(dict); 154 155 std::string json; 156 base::JSONWriter::Write(dict, &json); 157 158 return json; 159 } 160 161 scoped_refptr<ConvertableToTraceFormat> 162 TraceConfig::AsConvertableToTraceFormat() const { 163 return new ConvertableTraceConfigToTraceFormat(*this); 164 } 165 166 std::string TraceConfig::ToCategoryFilterString() const { 167 std::string filter_string; 168 WriteCategoryFilterString(included_categories_, &filter_string, true); 169 WriteCategoryFilterString(disabled_categories_, &filter_string, true); 170 WriteCategoryFilterString(excluded_categories_, &filter_string, false); 171 WriteCategoryFilterString(synthetic_delays_, &filter_string); 172 return filter_string; 173 } 174 175 bool TraceConfig::IsCategoryGroupEnabled( 176 const char* category_group_name) const { 177 // TraceLog should call this method only as part of enabling/disabling 178 // categories. 179 180 bool had_enabled_by_default = false; 181 DCHECK(category_group_name); 182 CStringTokenizer category_group_tokens( 183 category_group_name, category_group_name + strlen(category_group_name), 184 ","); 185 while (category_group_tokens.GetNext()) { 186 std::string category_group_token = category_group_tokens.token(); 187 // Don't allow empty tokens, nor tokens with leading or trailing space. 188 DCHECK(!TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace( 189 category_group_token)) 190 << "Disallowed category string"; 191 if (IsCategoryEnabled(category_group_token.c_str())) { 192 return true; 193 } 194 if (!base::MatchPattern(category_group_token.c_str(), 195 TRACE_DISABLED_BY_DEFAULT("*"))) 196 had_enabled_by_default = true; 197 } 198 // Do a second pass to check for explicitly disabled categories 199 // (those explicitly enabled have priority due to first pass). 200 category_group_tokens.Reset(); 201 bool category_group_disabled = false; 202 while (category_group_tokens.GetNext()) { 203 std::string category_group_token = category_group_tokens.token(); 204 for (StringList::const_iterator ci = excluded_categories_.begin(); 205 ci != excluded_categories_.end(); 206 ++ci) { 207 if (base::MatchPattern(category_group_token.c_str(), ci->c_str())) { 208 // Current token of category_group_name is present in excluded_list. 209 // Flag the exclusion and proceed further to check if any of the 210 // remaining categories of category_group_name is not present in the 211 // excluded_ list. 212 category_group_disabled = true; 213 break; 214 } 215 // One of the category of category_group_name is not present in 216 // excluded_ list. So, if it's not a disabled-by-default category, 217 // it has to be included_ list. Enable the category_group_name 218 // for recording. 219 if (!base::MatchPattern(category_group_token.c_str(), 220 TRACE_DISABLED_BY_DEFAULT("*"))) { 221 category_group_disabled = false; 222 } 223 } 224 // One of the categories present in category_group_name is not present in 225 // excluded_ list. Implies this category_group_name group can be enabled 226 // for recording, since one of its groups is enabled for recording. 227 if (!category_group_disabled) 228 break; 229 } 230 // If the category group is not excluded, and there are no included patterns 231 // we consider this category group enabled, as long as it had categories 232 // other than disabled-by-default. 233 return !category_group_disabled && 234 included_categories_.empty() && had_enabled_by_default; 235 } 236 237 void TraceConfig::Merge(const TraceConfig& config) { 238 if (record_mode_ != config.record_mode_ 239 || enable_sampling_ != config.enable_sampling_ 240 || enable_systrace_ != config.enable_systrace_ 241 || enable_argument_filter_ != config.enable_argument_filter_) { 242 DLOG(ERROR) << "Attempting to merge trace config with a different " 243 << "set of options."; 244 } 245 246 // Keep included patterns only if both filters have an included entry. 247 // Otherwise, one of the filter was specifying "*" and we want to honor the 248 // broadest filter. 249 if (HasIncludedPatterns() && config.HasIncludedPatterns()) { 250 included_categories_.insert(included_categories_.end(), 251 config.included_categories_.begin(), 252 config.included_categories_.end()); 253 } else { 254 included_categories_.clear(); 255 } 256 257 memory_dump_config_.insert(memory_dump_config_.end(), 258 config.memory_dump_config_.begin(), 259 config.memory_dump_config_.end()); 260 261 disabled_categories_.insert(disabled_categories_.end(), 262 config.disabled_categories_.begin(), 263 config.disabled_categories_.end()); 264 excluded_categories_.insert(excluded_categories_.end(), 265 config.excluded_categories_.begin(), 266 config.excluded_categories_.end()); 267 synthetic_delays_.insert(synthetic_delays_.end(), 268 config.synthetic_delays_.begin(), 269 config.synthetic_delays_.end()); 270 } 271 272 void TraceConfig::Clear() { 273 record_mode_ = RECORD_UNTIL_FULL; 274 enable_sampling_ = false; 275 enable_systrace_ = false; 276 enable_argument_filter_ = false; 277 included_categories_.clear(); 278 disabled_categories_.clear(); 279 excluded_categories_.clear(); 280 synthetic_delays_.clear(); 281 memory_dump_config_.clear(); 282 } 283 284 void TraceConfig::InitializeDefault() { 285 record_mode_ = RECORD_UNTIL_FULL; 286 enable_sampling_ = false; 287 enable_systrace_ = false; 288 enable_argument_filter_ = false; 289 excluded_categories_.push_back("*Debug"); 290 excluded_categories_.push_back("*Test"); 291 } 292 293 void TraceConfig::InitializeFromConfigString(const std::string& config_string) { 294 scoped_ptr<base::Value> value(base::JSONReader::Read(config_string)); 295 if (!value || !value->IsType(base::Value::TYPE_DICTIONARY)) { 296 InitializeDefault(); 297 return; 298 } 299 scoped_ptr<base::DictionaryValue> dict( 300 static_cast<base::DictionaryValue*>(value.release())); 301 302 record_mode_ = RECORD_UNTIL_FULL; 303 std::string record_mode; 304 if (dict->GetString(kRecordModeParam, &record_mode)) { 305 if (record_mode == kRecordUntilFull) { 306 record_mode_ = RECORD_UNTIL_FULL; 307 } else if (record_mode == kRecordContinuously) { 308 record_mode_ = RECORD_CONTINUOUSLY; 309 } else if (record_mode == kTraceToConsole) { 310 record_mode_ = ECHO_TO_CONSOLE; 311 } else if (record_mode == kRecordAsMuchAsPossible) { 312 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE; 313 } 314 } 315 316 bool enable_sampling; 317 if (!dict->GetBoolean(kEnableSamplingParam, &enable_sampling)) 318 enable_sampling_ = false; 319 else 320 enable_sampling_ = enable_sampling; 321 322 bool enable_systrace; 323 if (!dict->GetBoolean(kEnableSystraceParam, &enable_systrace)) 324 enable_systrace_ = false; 325 else 326 enable_systrace_ = enable_systrace; 327 328 bool enable_argument_filter; 329 if (!dict->GetBoolean(kEnableArgumentFilterParam, &enable_argument_filter)) 330 enable_argument_filter_ = false; 331 else 332 enable_argument_filter_ = enable_argument_filter; 333 334 base::ListValue* category_list = nullptr; 335 if (dict->GetList(kIncludedCategoriesParam, &category_list)) 336 SetCategoriesFromIncludedList(*category_list); 337 if (dict->GetList(kExcludedCategoriesParam, &category_list)) 338 SetCategoriesFromExcludedList(*category_list); 339 if (dict->GetList(kSyntheticDelaysParam, &category_list)) 340 SetSyntheticDelaysFromList(*category_list); 341 342 if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) { 343 // If dump triggers not set, the client is using the legacy with just 344 // category enabled. So, use the default periodic dump config. 345 base::DictionaryValue* memory_dump_config = nullptr; 346 if (dict->GetDictionary(kMemoryDumpConfigParam, &memory_dump_config)) 347 SetMemoryDumpConfig(*memory_dump_config); 348 else 349 SetDefaultMemoryDumpConfig(); 350 } 351 } 352 353 void TraceConfig::InitializeFromStrings( 354 const std::string& category_filter_string, 355 const std::string& trace_options_string) { 356 if (!category_filter_string.empty()) { 357 std::vector<std::string> split = base::SplitString( 358 category_filter_string, ",", base::TRIM_WHITESPACE, 359 base::SPLIT_WANT_ALL); 360 std::vector<std::string>::iterator iter; 361 for (iter = split.begin(); iter != split.end(); ++iter) { 362 std::string category = *iter; 363 // Ignore empty categories. 364 if (category.empty()) 365 continue; 366 // Synthetic delays are of the form 'DELAY(delay;option;option;...)'. 367 if (category.find(kSyntheticDelayCategoryFilterPrefix) == 0 && 368 category.at(category.size() - 1) == ')') { 369 category = category.substr( 370 strlen(kSyntheticDelayCategoryFilterPrefix), 371 category.size() - strlen(kSyntheticDelayCategoryFilterPrefix) - 1); 372 size_t name_length = category.find(';'); 373 if (name_length != std::string::npos && name_length > 0 && 374 name_length != category.size() - 1) { 375 synthetic_delays_.push_back(category); 376 } 377 } else if (category.at(0) == '-') { 378 // Excluded categories start with '-'. 379 // Remove '-' from category string. 380 category = category.substr(1); 381 excluded_categories_.push_back(category); 382 } else if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), 383 TRACE_DISABLED_BY_DEFAULT("")) == 0) { 384 disabled_categories_.push_back(category); 385 } else { 386 included_categories_.push_back(category); 387 } 388 } 389 } 390 391 record_mode_ = RECORD_UNTIL_FULL; 392 enable_sampling_ = false; 393 enable_systrace_ = false; 394 enable_argument_filter_ = false; 395 if(!trace_options_string.empty()) { 396 std::vector<std::string> split = base::SplitString( 397 trace_options_string, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL); 398 std::vector<std::string>::iterator iter; 399 for (iter = split.begin(); iter != split.end(); ++iter) { 400 if (*iter == kRecordUntilFull) { 401 record_mode_ = RECORD_UNTIL_FULL; 402 } else if (*iter == kRecordContinuously) { 403 record_mode_ = RECORD_CONTINUOUSLY; 404 } else if (*iter == kTraceToConsole) { 405 record_mode_ = ECHO_TO_CONSOLE; 406 } else if (*iter == kRecordAsMuchAsPossible) { 407 record_mode_ = RECORD_AS_MUCH_AS_POSSIBLE; 408 } else if (*iter == kEnableSampling) { 409 enable_sampling_ = true; 410 } else if (*iter == kEnableSystrace) { 411 enable_systrace_ = true; 412 } else if (*iter == kEnableArgumentFilter) { 413 enable_argument_filter_ = true; 414 } 415 } 416 } 417 418 if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) { 419 SetDefaultMemoryDumpConfig(); 420 } 421 } 422 423 void TraceConfig::SetCategoriesFromIncludedList( 424 const base::ListValue& included_list) { 425 included_categories_.clear(); 426 for (size_t i = 0; i < included_list.GetSize(); ++i) { 427 std::string category; 428 if (!included_list.GetString(i, &category)) 429 continue; 430 if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")), 431 TRACE_DISABLED_BY_DEFAULT("")) == 0) { 432 disabled_categories_.push_back(category); 433 } else { 434 included_categories_.push_back(category); 435 } 436 } 437 } 438 439 void TraceConfig::SetCategoriesFromExcludedList( 440 const base::ListValue& excluded_list) { 441 excluded_categories_.clear(); 442 for (size_t i = 0; i < excluded_list.GetSize(); ++i) { 443 std::string category; 444 if (excluded_list.GetString(i, &category)) 445 excluded_categories_.push_back(category); 446 } 447 } 448 449 void TraceConfig::SetSyntheticDelaysFromList(const base::ListValue& list) { 450 synthetic_delays_.clear(); 451 for (size_t i = 0; i < list.GetSize(); ++i) { 452 std::string delay; 453 if (!list.GetString(i, &delay)) 454 continue; 455 // Synthetic delays are of the form "delay;option;option;...". 456 size_t name_length = delay.find(';'); 457 if (name_length != std::string::npos && name_length > 0 && 458 name_length != delay.size() - 1) { 459 synthetic_delays_.push_back(delay); 460 } 461 } 462 } 463 464 void TraceConfig::AddCategoryToDict(base::DictionaryValue& dict, 465 const char* param, 466 const StringList& categories) const { 467 if (categories.empty()) 468 return; 469 470 scoped_ptr<base::ListValue> list(new base::ListValue()); 471 for (StringList::const_iterator ci = categories.begin(); 472 ci != categories.end(); 473 ++ci) { 474 list->AppendString(*ci); 475 } 476 477 dict.Set(param, std::move(list)); 478 } 479 480 void TraceConfig::SetMemoryDumpConfig( 481 const base::DictionaryValue& memory_dump_config) { 482 memory_dump_config_.clear(); 483 484 const base::ListValue* trigger_list = nullptr; 485 if (!memory_dump_config.GetList(kTriggersParam, &trigger_list) || 486 trigger_list->GetSize() == 0) { 487 return; 488 } 489 490 for (size_t i = 0; i < trigger_list->GetSize(); ++i) { 491 const base::DictionaryValue* trigger = nullptr; 492 if (!trigger_list->GetDictionary(i, &trigger)) 493 continue; 494 495 MemoryDumpTriggerConfig dump_config; 496 int interval = 0; 497 498 if (!trigger->GetInteger(kPeriodicIntervalParam, &interval)) { 499 continue; 500 } 501 DCHECK_GT(interval, 0); 502 dump_config.periodic_interval_ms = static_cast<uint32_t>(interval); 503 std::string level_of_detail_str; 504 trigger->GetString(kModeParam, &level_of_detail_str); 505 dump_config.level_of_detail = 506 StringToMemoryDumpLevelOfDetail(level_of_detail_str); 507 memory_dump_config_.push_back(dump_config); 508 } 509 } 510 511 void TraceConfig::SetDefaultMemoryDumpConfig() { 512 memory_dump_config_.clear(); 513 memory_dump_config_.push_back(kDefaultHeavyMemoryDumpTrigger); 514 memory_dump_config_.push_back(kDefaultLightMemoryDumpTrigger); 515 } 516 517 void TraceConfig::ToDict(base::DictionaryValue& dict) const { 518 switch (record_mode_) { 519 case RECORD_UNTIL_FULL: 520 dict.SetString(kRecordModeParam, kRecordUntilFull); 521 break; 522 case RECORD_CONTINUOUSLY: 523 dict.SetString(kRecordModeParam, kRecordContinuously); 524 break; 525 case RECORD_AS_MUCH_AS_POSSIBLE: 526 dict.SetString(kRecordModeParam, kRecordAsMuchAsPossible); 527 break; 528 case ECHO_TO_CONSOLE: 529 dict.SetString(kRecordModeParam, kTraceToConsole); 530 break; 531 default: 532 NOTREACHED(); 533 } 534 535 if (enable_sampling_) 536 dict.SetBoolean(kEnableSamplingParam, true); 537 else 538 dict.SetBoolean(kEnableSamplingParam, false); 539 540 if (enable_systrace_) 541 dict.SetBoolean(kEnableSystraceParam, true); 542 else 543 dict.SetBoolean(kEnableSystraceParam, false); 544 545 if (enable_argument_filter_) 546 dict.SetBoolean(kEnableArgumentFilterParam, true); 547 else 548 dict.SetBoolean(kEnableArgumentFilterParam, false); 549 550 StringList categories(included_categories_); 551 categories.insert(categories.end(), 552 disabled_categories_.begin(), 553 disabled_categories_.end()); 554 AddCategoryToDict(dict, kIncludedCategoriesParam, categories); 555 AddCategoryToDict(dict, kExcludedCategoriesParam, excluded_categories_); 556 AddCategoryToDict(dict, kSyntheticDelaysParam, synthetic_delays_); 557 558 if (IsCategoryEnabled(MemoryDumpManager::kTraceCategory)) { 559 scoped_ptr<base::DictionaryValue> memory_dump_config( 560 new base::DictionaryValue()); 561 scoped_ptr<base::ListValue> triggers_list(new base::ListValue()); 562 for (const MemoryDumpTriggerConfig& config : memory_dump_config_) { 563 scoped_ptr<base::DictionaryValue> trigger_dict( 564 new base::DictionaryValue()); 565 trigger_dict->SetInteger(kPeriodicIntervalParam, 566 static_cast<int>(config.periodic_interval_ms)); 567 trigger_dict->SetString( 568 kModeParam, MemoryDumpLevelOfDetailToString(config.level_of_detail)); 569 triggers_list->Append(std::move(trigger_dict)); 570 } 571 572 // Empty triggers will still be specified explicitly since it means that 573 // the periodic dumps are not enabled. 574 memory_dump_config->Set(kTriggersParam, std::move(triggers_list)); 575 dict.Set(kMemoryDumpConfigParam, std::move(memory_dump_config)); 576 } 577 } 578 579 std::string TraceConfig::ToTraceOptionsString() const { 580 std::string ret; 581 switch (record_mode_) { 582 case RECORD_UNTIL_FULL: 583 ret = kRecordUntilFull; 584 break; 585 case RECORD_CONTINUOUSLY: 586 ret = kRecordContinuously; 587 break; 588 case RECORD_AS_MUCH_AS_POSSIBLE: 589 ret = kRecordAsMuchAsPossible; 590 break; 591 case ECHO_TO_CONSOLE: 592 ret = kTraceToConsole; 593 break; 594 default: 595 NOTREACHED(); 596 } 597 if (enable_sampling_) 598 ret = ret + "," + kEnableSampling; 599 if (enable_systrace_) 600 ret = ret + "," + kEnableSystrace; 601 if (enable_argument_filter_) 602 ret = ret + "," + kEnableArgumentFilter; 603 return ret; 604 } 605 606 void TraceConfig::WriteCategoryFilterString(const StringList& values, 607 std::string* out, 608 bool included) const { 609 bool prepend_comma = !out->empty(); 610 int token_cnt = 0; 611 for (StringList::const_iterator ci = values.begin(); 612 ci != values.end(); ++ci) { 613 if (token_cnt > 0 || prepend_comma) 614 StringAppendF(out, ","); 615 StringAppendF(out, "%s%s", (included ? "" : "-"), ci->c_str()); 616 ++token_cnt; 617 } 618 } 619 620 void TraceConfig::WriteCategoryFilterString(const StringList& delays, 621 std::string* out) const { 622 bool prepend_comma = !out->empty(); 623 int token_cnt = 0; 624 for (StringList::const_iterator ci = delays.begin(); 625 ci != delays.end(); ++ci) { 626 if (token_cnt > 0 || prepend_comma) 627 StringAppendF(out, ","); 628 StringAppendF(out, "%s%s)", kSyntheticDelayCategoryFilterPrefix, 629 ci->c_str()); 630 ++token_cnt; 631 } 632 } 633 634 bool TraceConfig::IsCategoryEnabled(const char* category_name) const { 635 StringList::const_iterator ci; 636 637 // Check the disabled- filters and the disabled-* wildcard first so that a 638 // "*" filter does not include the disabled. 639 for (ci = disabled_categories_.begin(); 640 ci != disabled_categories_.end(); 641 ++ci) { 642 if (base::MatchPattern(category_name, ci->c_str())) 643 return true; 644 } 645 646 if (base::MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*"))) 647 return false; 648 649 for (ci = included_categories_.begin(); 650 ci != included_categories_.end(); 651 ++ci) { 652 if (base::MatchPattern(category_name, ci->c_str())) 653 return true; 654 } 655 656 return false; 657 } 658 659 bool TraceConfig::IsEmptyOrContainsLeadingOrTrailingWhitespace( 660 const std::string& str) { 661 return str.empty() || 662 str.at(0) == ' ' || 663 str.at(str.length() - 1) == ' '; 664 } 665 666 bool TraceConfig::HasIncludedPatterns() const { 667 return !included_categories_.empty(); 668 } 669 670 } // namespace trace_event 671 } // namespace base 672