trace_config_category_filter.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. // Copyright 2017 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. #include "base/trace_event/trace_config_category_filter.h"
  5. #include "base/memory/ptr_util.h"
  6. #include "base/strings/pattern.h"
  7. #include "base/strings/string_piece.h"
  8. #include "base/strings/string_split.h"
  9. #include "base/strings/string_tokenizer.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/trace_event/trace_event.h"
  13. namespace base {
  14. namespace trace_event {
  15. namespace {
  16. const char kIncludedCategoriesParam[] = "included_categories";
  17. const char kExcludedCategoriesParam[] = "excluded_categories";
  18. }
  19. TraceConfigCategoryFilter::TraceConfigCategoryFilter() = default;
  20. TraceConfigCategoryFilter::TraceConfigCategoryFilter(
  21. const TraceConfigCategoryFilter& other) = default;
  22. TraceConfigCategoryFilter::~TraceConfigCategoryFilter() = default;
  23. TraceConfigCategoryFilter& TraceConfigCategoryFilter::operator=(
  24. const TraceConfigCategoryFilter& rhs) = default;
  25. void TraceConfigCategoryFilter::InitializeFromString(
  26. const StringPiece& category_filter_string) {
  27. std::vector<StringPiece> split = SplitStringPiece(
  28. category_filter_string, ",", TRIM_WHITESPACE, SPLIT_WANT_ALL);
  29. for (const StringPiece& category : split) {
  30. // Ignore empty categories.
  31. if (category.empty())
  32. continue;
  33. if (category.front() == '-') {
  34. // Excluded categories start with '-'.
  35. // Remove '-' from category string.
  36. excluded_categories_.emplace_back(category.substr(1));
  37. } else if (StartsWith(category, TRACE_DISABLED_BY_DEFAULT(""))) {
  38. disabled_categories_.emplace_back(category);
  39. } else {
  40. included_categories_.emplace_back(category);
  41. }
  42. }
  43. }
  44. void TraceConfigCategoryFilter::InitializeFromConfigDict(const Value& dict) {
  45. const Value* included_category_list =
  46. dict.FindListKey(kIncludedCategoriesParam);
  47. if (included_category_list)
  48. SetCategoriesFromIncludedList(*included_category_list);
  49. const Value* excluded_category_list =
  50. dict.FindListKey(kExcludedCategoriesParam);
  51. if (excluded_category_list)
  52. SetCategoriesFromExcludedList(*excluded_category_list);
  53. }
  54. bool TraceConfigCategoryFilter::IsCategoryGroupEnabled(
  55. const StringPiece& category_group_name) const {
  56. bool had_enabled_by_default = false;
  57. DCHECK(!category_group_name.empty());
  58. CStringTokenizer category_group_tokens(category_group_name.begin(),
  59. category_group_name.end(), ",");
  60. while (category_group_tokens.GetNext()) {
  61. StringPiece category_group_token = category_group_tokens.token_piece();
  62. // Don't allow empty tokens, nor tokens with leading or trailing space.
  63. DCHECK(IsCategoryNameAllowed(category_group_token))
  64. << "Disallowed category string";
  65. if (IsCategoryEnabled(category_group_token))
  66. return true;
  67. if (!MatchPattern(category_group_token, TRACE_DISABLED_BY_DEFAULT("*")))
  68. had_enabled_by_default = true;
  69. }
  70. // Do a second pass to check for explicitly disabled categories
  71. // (those explicitly enabled have priority due to first pass).
  72. category_group_tokens.Reset();
  73. bool category_group_disabled = false;
  74. while (category_group_tokens.GetNext()) {
  75. StringPiece category_group_token = category_group_tokens.token_piece();
  76. for (const std::string& category : excluded_categories_) {
  77. if (MatchPattern(category_group_token, category)) {
  78. // Current token of category_group_name is present in excluded_list.
  79. // Flag the exclusion and proceed further to check if any of the
  80. // remaining categories of category_group_name is not present in the
  81. // excluded_ list.
  82. category_group_disabled = true;
  83. break;
  84. }
  85. // One of the category of category_group_name is not present in
  86. // excluded_ list. So, if it's not a disabled-by-default category,
  87. // it has to be included_ list. Enable the category_group_name
  88. // for recording.
  89. if (!MatchPattern(category_group_token, TRACE_DISABLED_BY_DEFAULT("*")))
  90. category_group_disabled = false;
  91. }
  92. // One of the categories present in category_group_name is not present in
  93. // excluded_ list. Implies this category_group_name group can be enabled
  94. // for recording, since one of its groups is enabled for recording.
  95. if (!category_group_disabled)
  96. break;
  97. }
  98. // If the category group is not excluded, and there are no included patterns
  99. // we consider this category group enabled, as long as it had categories
  100. // other than disabled-by-default.
  101. return !category_group_disabled && had_enabled_by_default &&
  102. included_categories_.empty();
  103. }
  104. bool TraceConfigCategoryFilter::IsCategoryEnabled(
  105. const StringPiece& category_name) const {
  106. // Check the disabled- filters and the disabled-* wildcard first so that a
  107. // "*" filter does not include the disabled.
  108. for (const std::string& category : disabled_categories_) {
  109. if (MatchPattern(category_name, category))
  110. return true;
  111. }
  112. if (MatchPattern(category_name, TRACE_DISABLED_BY_DEFAULT("*")))
  113. return false;
  114. for (const std::string& category : included_categories_) {
  115. if (MatchPattern(category_name, category))
  116. return true;
  117. }
  118. return false;
  119. }
  120. void TraceConfigCategoryFilter::Merge(const TraceConfigCategoryFilter& config) {
  121. // Keep included patterns only if both filters have an included entry.
  122. // Otherwise, one of the filter was specifying "*" and we want to honor the
  123. // broadest filter.
  124. if (!included_categories_.empty() && !config.included_categories_.empty()) {
  125. included_categories_.insert(included_categories_.end(),
  126. config.included_categories_.begin(),
  127. config.included_categories_.end());
  128. } else {
  129. included_categories_.clear();
  130. }
  131. disabled_categories_.insert(disabled_categories_.end(),
  132. config.disabled_categories_.begin(),
  133. config.disabled_categories_.end());
  134. excluded_categories_.insert(excluded_categories_.end(),
  135. config.excluded_categories_.begin(),
  136. config.excluded_categories_.end());
  137. }
  138. void TraceConfigCategoryFilter::Clear() {
  139. included_categories_.clear();
  140. disabled_categories_.clear();
  141. excluded_categories_.clear();
  142. }
  143. void TraceConfigCategoryFilter::ToDict(Value::Dict& dict) const {
  144. StringList categories(included_categories_);
  145. categories.insert(categories.end(), disabled_categories_.begin(),
  146. disabled_categories_.end());
  147. AddCategoriesToDict(categories, kIncludedCategoriesParam, dict);
  148. AddCategoriesToDict(excluded_categories_, kExcludedCategoriesParam, dict);
  149. }
  150. std::string TraceConfigCategoryFilter::ToFilterString() const {
  151. std::string filter_string;
  152. WriteCategoryFilterString(included_categories_, &filter_string, true);
  153. WriteCategoryFilterString(disabled_categories_, &filter_string, true);
  154. WriteCategoryFilterString(excluded_categories_, &filter_string, false);
  155. return filter_string;
  156. }
  157. void TraceConfigCategoryFilter::SetCategoriesFromIncludedList(
  158. const Value& included_list) {
  159. included_categories_.clear();
  160. for (const Value& item : included_list.GetListDeprecated()) {
  161. if (!item.is_string())
  162. continue;
  163. const std::string& category = item.GetString();
  164. if (category.compare(0, strlen(TRACE_DISABLED_BY_DEFAULT("")),
  165. TRACE_DISABLED_BY_DEFAULT("")) == 0) {
  166. disabled_categories_.push_back(category);
  167. } else {
  168. included_categories_.push_back(category);
  169. }
  170. }
  171. }
  172. void TraceConfigCategoryFilter::SetCategoriesFromExcludedList(
  173. const Value& excluded_list) {
  174. excluded_categories_.clear();
  175. for (const Value& item : excluded_list.GetListDeprecated()) {
  176. if (item.is_string())
  177. excluded_categories_.push_back(item.GetString());
  178. }
  179. }
  180. void TraceConfigCategoryFilter::AddCategoriesToDict(
  181. const StringList& categories,
  182. const char* param,
  183. Value::Dict& dict) const {
  184. if (categories.empty())
  185. return;
  186. Value::List list;
  187. for (const std::string& category : categories)
  188. list.Append(category);
  189. dict.Set(param, std::move(list));
  190. }
  191. void TraceConfigCategoryFilter::WriteCategoryFilterString(
  192. const StringList& values,
  193. std::string* out,
  194. bool included) const {
  195. bool prepend_comma = !out->empty();
  196. int token_cnt = 0;
  197. for (const std::string& category : values) {
  198. if (token_cnt > 0 || prepend_comma)
  199. StringAppendF(out, ",");
  200. StringAppendF(out, "%s%s", (included ? "" : "-"), category.c_str());
  201. ++token_cnt;
  202. }
  203. }
  204. // static
  205. bool TraceConfigCategoryFilter::IsCategoryNameAllowed(StringPiece str) {
  206. return !str.empty() && str.front() != ' ' && str.back() != ' ';
  207. }
  208. } // namespace trace_event
  209. } // namespace base