summaryrefslogtreecommitdiffstats
path: root/base/debug
diff options
context:
space:
mode:
authorjbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-12 22:03:41 +0000
committerjbates@chromium.org <jbates@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-12 22:03:41 +0000
commit434b02a20e5194548f6ab5868b78f14215e3614d (patch)
tree1003e850e6fce0d84697c600e78186b09029f0fd /base/debug
parent8665da83c740dbcf8bd260f4759ca7b5b283b995 (diff)
downloadchromium_src-434b02a20e5194548f6ab5868b78f14215e3614d.zip
chromium_src-434b02a20e5194548f6ab5868b78f14215e3614d.tar.gz
chromium_src-434b02a20e5194548f6ab5868b78f14215e3614d.tar.bz2
Add support for filtering traces by categories. The TraceLog API is updated to support included and excluded categories. This API is then plumbed through to the TraceController so that it can be used across all processes.
BUG=96122 TEST=base_unittests Review URL: http://codereview.chromium.org/7867013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@100777 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/debug')
-rw-r--r--base/debug/trace_event.cc99
-rw-r--r--base/debug/trace_event.h22
-rw-r--r--base/debug/trace_event_unittest.cc161
3 files changed, 253 insertions, 29 deletions
diff --git a/base/debug/trace_event.cc b/base/debug/trace_event.cc
index 6529592..879f3a9 100644
--- a/base/debug/trace_event.cc
+++ b/base/debug/trace_event.cc
@@ -28,7 +28,7 @@ namespace debug {
const size_t kTraceEventBufferSize = 500000;
const size_t kTraceEventBatchSize = 1000;
-#define TRACE_EVENT_MAX_CATEGORIES 42
+#define TRACE_EVENT_MAX_CATEGORIES 100
static TraceCategory g_categories[TRACE_EVENT_MAX_CATEGORIES] = {
{ "tracing already shutdown", false },
@@ -279,9 +279,31 @@ const TraceCategory* TraceLog::GetCategory(const char* name) {
return tracelog->GetCategoryInternal(name);
}
+static void EnableMatchingCategory(int category_index,
+ const std::vector<std::string>& patterns,
+ bool is_included) {
+ std::vector<std::string>::const_iterator ci = patterns.begin();
+ bool is_match = false;
+ for (; ci != patterns.end(); ++ci) {
+ is_match = MatchPattern(g_categories[category_index].name, ci->c_str());
+ if (is_match)
+ break;
+ }
+ g_categories[category_index].enabled = is_match? is_included : !is_included;
+}
+
+// Enable/disable each category based on the category filters in |patterns|.
+// If the category name matches one of the patterns, its enabled status is set
+// to |is_included|. Otherwise its enabled status is set to !|is_included|.
+static void EnableMatchingCategories(const std::vector<std::string>& patterns,
+ bool is_included) {
+ for (int i = 0; i < g_category_index; i++)
+ EnableMatchingCategory(i, patterns, is_included);
+}
+
const TraceCategory* TraceLog::GetCategoryInternal(const char* name) {
AutoLock lock(lock_);
- DCHECK(!strchr(name, '"')) << "Names may not contain double quote char";
+ DCHECK(!strchr(name, '"')) << "Category names may not contain double quote";
// Search for pre-existing category matching this name
for (int i = 0; i < g_category_index; i++) {
@@ -296,32 +318,65 @@ const TraceCategory* TraceLog::GetCategoryInternal(const char* name) {
int new_index = g_category_index++;
g_categories[new_index].name = name;
DCHECK(!g_categories[new_index].enabled);
- g_categories[new_index].enabled = enabled_;
+ if (enabled_) {
+ // Note that if both included and excluded_categories are empty, the else
+ // clause below excludes nothing, thereby enabling this category.
+ if (!included_categories_.empty())
+ EnableMatchingCategory(new_index, included_categories_, true);
+ else
+ EnableMatchingCategory(new_index, excluded_categories_, false);
+ } else {
+ g_categories[new_index].enabled = false;
+ }
return &g_categories[new_index];
} else {
return g_category_categories_exhausted;
}
}
-void TraceLog::SetEnabled(bool enabled) {
+void TraceLog::GetKnownCategories(std::vector<std::string>* categories) {
+ AutoLock lock(lock_);
+ for (int i = 0; i < g_category_index; i++)
+ categories->push_back(g_categories[i].name);
+}
+
+void TraceLog::SetEnabled(const std::vector<std::string>& included_categories,
+ const std::vector<std::string>& excluded_categories) {
+ AutoLock lock(lock_);
+ if (enabled_)
+ return;
+ logged_events_.reserve(1024);
+ enabled_ = true;
+ included_categories_ = included_categories;
+ excluded_categories_ = excluded_categories;
+ // Note that if both included and excluded_categories are empty, the else
+ // clause below excludes nothing, thereby enabling all categories.
+ if (!included_categories_.empty())
+ EnableMatchingCategories(included_categories_, true);
+ else
+ EnableMatchingCategories(excluded_categories_, false);
+}
+
+void TraceLog::SetDisabled() {
{
AutoLock lock(lock_);
- if (enabled == enabled_)
+ if (!enabled_)
return;
- logged_events_.reserve(1024);
- enabled_ = enabled;
- for (int i = 0; i < g_category_index; i++) {
- //TODO(scheib): If changed to enable specific categories instead of all
- // check GetCategoryInternal creation code that users TraceLog::enabled_
- g_categories[i].enabled = enabled;
- }
+ enabled_ = false;
+ included_categories_.clear();
+ excluded_categories_.clear();
+ for (int i = 0; i < g_category_index; i++)
+ g_categories[i].enabled = false;
+ AddCurrentMetadataEvents();
+ } // release lock
+ Flush();
+}
- if (!enabled)
- AddCurrentMetadataEvents();
- } // release lock
- if (!enabled) {
- Flush();
- }
+void TraceLog::SetEnabled(bool enabled) {
+ if (enabled)
+ SetEnabled(std::vector<std::string>(), std::vector<std::string>());
+ else
+ SetDisabled();
}
float TraceLog::GetBufferPercentFull() const {
@@ -346,7 +401,7 @@ void TraceLog::Flush() {
AutoLock lock(lock_);
previous_logged_events.swap(logged_events_);
output_callback_copy = output_callback_;
- } // release lock
+ } // release lock
if (output_callback_copy.is_null())
return;
@@ -382,7 +437,7 @@ int TraceLog::AddTraceEvent(TraceEventPhase phase,
int ret_begin_id = -1;
{
AutoLock lock(lock_);
- if (!enabled_ || !category->enabled)
+ if (!category->enabled)
return -1;
if (logged_events_.size() >= kTraceEventBufferSize)
return -1;
@@ -441,7 +496,7 @@ int TraceLog::AddTraceEvent(TraceEventPhase phase,
if (logged_events_.size() == kTraceEventBufferSize) {
buffer_full_callback_copy = buffer_full_callback_;
}
- } // release lock
+ } // release lock
if (!buffer_full_callback_copy.is_null())
buffer_full_callback_copy.Run();
@@ -541,7 +596,7 @@ void TraceEndOnScopeCloseThreshold::AddEventIfEnabled() {
}
}
-} // namespace internal
+} // namespace internal
} // namespace debug
} // namespace base
diff --git a/base/debug/trace_event.h b/base/debug/trace_event.h
index 380f5e7..e7b3f90 100644
--- a/base/debug/trace_event.h
+++ b/base/debug/trace_event.h
@@ -509,9 +509,23 @@ class BASE_EXPORT TraceLog {
static TraceLog* GetInstance();
- // Global enable of tracing. Currently enables all categories or not.
- // TODO(scheib): Replace with an Enable/DisableCategory() that
- // implicitly controls the global logging state.
+ // Get set of known categories. This can change as new code paths are reached.
+ // The known categories are inserted into |categories|.
+ void GetKnownCategories(std::vector<std::string>* categories);
+
+ // Enable tracing for provided list of categories. If tracing is already
+ // enabled, this method does nothing -- changing categories during trace is
+ // not supported.
+ // If both included_categories and excluded_categories are empty,
+ // all categories are traced.
+ // Else if included_categories is non-empty, only those are traced.
+ // Else if excluded_categories is non-empty, everything but those are traced.
+ // Wildcards * and ? are supported (see MatchPattern in string_util.h).
+ void SetEnabled(const std::vector<std::string>& included_categories,
+ const std::vector<std::string>& excluded_categories);
+ // Disable tracing for all categories.
+ void SetDisabled();
+ // Helper method to enable/disable tracing for all categories.
void SetEnabled(bool enabled);
bool IsEnabled() { return enabled_; }
@@ -590,6 +604,8 @@ class BASE_EXPORT TraceLog {
OutputCallback output_callback_;
BufferFullCallback buffer_full_callback_;
std::vector<TraceEvent> logged_events_;
+ std::vector<std::string> included_categories_;
+ std::vector<std::string> excluded_categories_;
base::hash_map<PlatformThreadId, std::string> thread_names_;
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index 839b19a..a5c889f 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -23,9 +23,15 @@ namespace debug {
namespace {
+enum CompareOp {
+ IS_EQUAL,
+ IS_NOT_EQUAL,
+};
+
struct JsonKeyValue {
const char* key;
const char* value;
+ CompareOp op;
};
class TraceEventTestFixture : public testing::Test {
@@ -37,6 +43,14 @@ class TraceEventTestFixture : public testing::Test {
scoped_refptr<TraceLog::RefCountedString> json_events_str);
bool FindMatchingTraceEntry(const JsonKeyValue* key_values);
bool FindNamePhase(const char* name, const char* phase);
+ bool FindMatchingValue(const char* key,
+ const char* value);
+ bool FindNonMatchingValue(const char* key,
+ const char* value);
+ void Clear() {
+ trace_string_.clear();
+ trace_parsed_.Clear();
+ }
std::string trace_string_;
ListValue trace_parsed_;
@@ -75,13 +89,27 @@ void TraceEventTestFixture::OnTraceDataCollected(
}
}
+static bool CompareJsonValues(const std::string& lhs,
+ const std::string& rhs,
+ CompareOp op) {
+ switch (op) {
+ case IS_EQUAL:
+ return lhs == rhs;
+ case IS_NOT_EQUAL:
+ return lhs != rhs;
+ default:
+ CHECK(0);
+ }
+ return false;
+}
+
static bool IsKeyValueInDict(const JsonKeyValue* key_value,
DictionaryValue* dict) {
Value* value = NULL;
std::string value_str;
if (dict->Get(key_value->key, &value) &&
value->GetAsString(&value_str) &&
- value_str == key_value->value)
+ CompareJsonValues(value_str, key_value->value, key_value->op))
return true;
// Recurse to test arguments
@@ -123,9 +151,27 @@ bool TraceEventTestFixture::FindMatchingTraceEntry(
bool TraceEventTestFixture::FindNamePhase(const char* name, const char* phase) {
JsonKeyValue key_values[] = {
- {"name", name},
- {"ph", phase},
- {0, 0}
+ {"name", name, IS_EQUAL},
+ {"ph", phase, IS_EQUAL},
+ {0, 0, IS_EQUAL}
+ };
+ return FindMatchingTraceEntry(key_values);
+}
+
+bool TraceEventTestFixture::FindMatchingValue(const char* key,
+ const char* value) {
+ JsonKeyValue key_values[] = {
+ {key, value, IS_EQUAL},
+ {0, 0, IS_EQUAL}
+ };
+ return FindMatchingTraceEntry(key_values);
+}
+
+bool TraceEventTestFixture::FindNonMatchingValue(const char* key,
+ const char* value) {
+ JsonKeyValue key_values[] = {
+ {key, value, IS_NOT_EQUAL},
+ {0, 0, IS_EQUAL}
};
return FindMatchingTraceEntry(key_values);
}
@@ -360,6 +406,113 @@ TEST_F(TraceEventTestFixture, DataCaptured) {
ValidateAllTraceMacrosCreatedData(trace_parsed_, trace_string_);
}
+// Test that categories work.
+TEST_F(TraceEventTestFixture, Categories) {
+ ManualTestSetUp();
+
+ // Test that categories that are used can be retrieved whether trace was
+ // enabled or disabled when the trace event was encountered.
+ TRACE_EVENT_INSTANT0("c1", "name");
+ TRACE_EVENT_INSTANT0("c2", "name");
+ TraceLog::GetInstance()->SetEnabled(true);
+ TRACE_EVENT_INSTANT0("c3", "name");
+ TRACE_EVENT_INSTANT0("c4", "name");
+ TraceLog::GetInstance()->SetEnabled(false);
+ std::vector<std::string> cats;
+ TraceLog::GetInstance()->GetKnownCategories(&cats);
+ EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c1") != cats.end());
+ EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c2") != cats.end());
+ EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c3") != cats.end());
+ EXPECT_TRUE(std::find(cats.begin(), cats.end(), "c4") != cats.end());
+
+ const std::vector<std::string> empty_categories;
+ std::vector<std::string> included_categories;
+ std::vector<std::string> excluded_categories;
+
+ // Test that category filtering works.
+
+ // Include nonexistent category -> no events
+ Clear();
+ included_categories.clear();
+ included_categories.push_back("not_found823564786");
+ TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
+ TRACE_EVENT_INSTANT0("cat1", "name");
+ TRACE_EVENT_INSTANT0("cat2", "name");
+ TraceLog::GetInstance()->SetDisabled();
+ EXPECT_TRUE(trace_parsed_.empty());
+
+ // Include existent category -> only events of that category
+ Clear();
+ included_categories.clear();
+ included_categories.push_back("inc");
+ TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
+ TRACE_EVENT_INSTANT0("inc", "name");
+ TRACE_EVENT_INSTANT0("inc2", "name");
+ TraceLog::GetInstance()->SetDisabled();
+ EXPECT_TRUE(FindMatchingValue("cat", "inc"));
+ EXPECT_FALSE(FindNonMatchingValue("cat", "inc"));
+
+ // Include existent wildcard -> all categories matching wildcard
+ Clear();
+ included_categories.clear();
+ included_categories.push_back("inc_wildcard_*");
+ included_categories.push_back("inc_wildchar_?_end");
+ TraceLog::GetInstance()->SetEnabled(included_categories, empty_categories);
+ TRACE_EVENT_INSTANT0("inc_wildcard_abc", "included");
+ TRACE_EVENT_INSTANT0("inc_wildcard_", "included");
+ TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "included");
+ TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "not_inc");
+ TRACE_EVENT_INSTANT0("cat1", "not_inc");
+ TRACE_EVENT_INSTANT0("cat2", "not_inc");
+ TraceLog::GetInstance()->SetDisabled();
+ EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_abc"));
+ EXPECT_TRUE(FindMatchingValue("cat", "inc_wildcard_"));
+ EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_x_end"));
+ EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
+
+ included_categories.clear();
+
+ // Exclude nonexistent category -> all events
+ Clear();
+ excluded_categories.clear();
+ excluded_categories.push_back("not_found823564786");
+ TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
+ TRACE_EVENT_INSTANT0("cat1", "name");
+ TRACE_EVENT_INSTANT0("cat2", "name");
+ TraceLog::GetInstance()->SetDisabled();
+ EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
+ EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
+
+ // Exclude existent category -> only events of other categories
+ Clear();
+ excluded_categories.clear();
+ excluded_categories.push_back("inc");
+ TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
+ TRACE_EVENT_INSTANT0("inc", "name");
+ TRACE_EVENT_INSTANT0("inc2", "name");
+ TraceLog::GetInstance()->SetDisabled();
+ EXPECT_TRUE(FindMatchingValue("cat", "inc2"));
+ EXPECT_FALSE(FindMatchingValue("cat", "inc"));
+
+ // Exclude existent wildcard -> all categories not matching wildcard
+ Clear();
+ excluded_categories.clear();
+ excluded_categories.push_back("inc_wildcard_*");
+ excluded_categories.push_back("inc_wildchar_?_end");
+ TraceLog::GetInstance()->SetEnabled(empty_categories, excluded_categories);
+ TRACE_EVENT_INSTANT0("inc_wildcard_abc", "not_inc");
+ TRACE_EVENT_INSTANT0("inc_wildcard_", "not_inc");
+ TRACE_EVENT_INSTANT0("inc_wildchar_x_end", "not_inc");
+ TRACE_EVENT_INSTANT0("inc_wildchar_bla_end", "included");
+ TRACE_EVENT_INSTANT0("cat1", "included");
+ TRACE_EVENT_INSTANT0("cat2", "included");
+ TraceLog::GetInstance()->SetDisabled();
+ EXPECT_TRUE(FindMatchingValue("cat", "inc_wildchar_bla_end"));
+ EXPECT_TRUE(FindMatchingValue("cat", "cat1"));
+ EXPECT_TRUE(FindMatchingValue("cat", "cat2"));
+ EXPECT_FALSE(FindMatchingValue("name", "not_inc"));
+}
+
// Simple Test for time threshold events.
TEST_F(TraceEventTestFixture, DataCapturedThreshold) {
ManualTestSetUp();