Index: base/trace_event/trace_log.cc |
diff --git a/base/trace_event/trace_log.cc b/base/trace_event/trace_log.cc |
index 872cd172b2b7310ef81b40befb90c06a3e7d5a90..a9f99d41f0dc97b37a1cc7364c30231451047088 100644 |
--- a/base/trace_event/trace_log.cc |
+++ b/base/trace_event/trace_log.cc |
@@ -16,6 +16,7 @@ |
#include "base/lazy_instance.h" |
#include "base/location.h" |
#include "base/macros.h" |
+#include "base/memory/ptr_util.h" |
#include "base/memory/ref_counted_memory.h" |
#include "base/memory/singleton.h" |
#include "base/process/process_metrics.h" |
@@ -102,6 +103,39 @@ const char* g_category_groups[MAX_CATEGORY_GROUPS] = { |
// The enabled flag is char instead of bool so that the API can be used from C. |
unsigned char g_category_group_enabled[MAX_CATEGORY_GROUPS] = {0}; |
+ |
+const char kEventNameWhitelist[] = "event_name_whitelist"; |
+ |
+class EventNameFilter : public TraceLog::TraceEventFilter { |
+ public: |
+ EventNameFilter(const base::DictionaryValue* filter_args) { |
+ const base::ListValue* whitelist = nullptr; |
+ if (filter_args->GetList(kEventNameWhitelist, &whitelist)) { |
+ for (size_t i = 0; i < whitelist->GetSize(); ++i) { |
+ std::string event_name; |
+ if (!whitelist->GetString(i, &event_name)) |
+ continue; |
+ |
+ whitelist_.insert(event_name); |
+ } |
+ } |
+ } |
+ |
+ bool FilterTraceEvent(const TraceEvent& trace_event) const override { |
+ return ContainsKey(whitelist_, trace_event.name()); |
+ } |
+ |
+ private: |
+ std::unordered_set<std::string> whitelist_; |
+}; |
+ |
+base::LazyInstance< |
+ std::list<std::unique_ptr<TraceLog::TraceEventFilter>>>::Leaky |
+ g_category_group_filter[MAX_CATEGORY_GROUPS] = {LAZY_INSTANCE_INITIALIZER}; |
+ |
+TraceLog::TraceEventFilterConstructorForTesting |
+ g_trace_event_filter_constructor_for_testing = nullptr; |
+ |
// Indexes here have to match the g_category_groups array indexes above. |
const int kCategoryAlreadyShutdown = 1; |
const int kCategoryCategoriesExhausted = 2; |
@@ -179,6 +213,22 @@ void MakeHandle(uint32_t chunk_seq, |
handle->event_index = static_cast<uint16_t>(event_index); |
} |
+uintptr_t GetCategoryIndex(const unsigned char* category_group_enabled) { |
+ // Calculate the index of the category group by finding |
+ // category_group_enabled in g_category_group_enabled array. |
+ uintptr_t category_begin = |
+ reinterpret_cast<uintptr_t>(g_category_group_enabled); |
+ uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled); |
+ DCHECK(category_ptr >= category_begin); |
+ DCHECK(category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled + |
+ MAX_CATEGORY_GROUPS)) |
+ << "out of bounds category pointer"; |
+ uintptr_t category_index = |
+ (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]); |
+ |
+ return category_index; |
+} |
+ |
} // namespace |
// A helper class that allows the lock to be acquired in the middle of the scope |
@@ -445,18 +495,13 @@ const unsigned char* TraceLog::GetCategoryGroupEnabled( |
const char* TraceLog::GetCategoryGroupName( |
const unsigned char* category_group_enabled) { |
- // Calculate the index of the category group by finding |
- // category_group_enabled in g_category_group_enabled array. |
- uintptr_t category_begin = |
- reinterpret_cast<uintptr_t>(g_category_group_enabled); |
- uintptr_t category_ptr = reinterpret_cast<uintptr_t>(category_group_enabled); |
- DCHECK(category_ptr >= category_begin); |
- DCHECK(category_ptr < reinterpret_cast<uintptr_t>(g_category_group_enabled + |
- MAX_CATEGORY_GROUPS)) |
- << "out of bounds category pointer"; |
- uintptr_t category_index = |
- (category_ptr - category_begin) / sizeof(g_category_group_enabled[0]); |
- return g_category_groups[category_index]; |
+ return g_category_groups[GetCategoryIndex(category_group_enabled)]; |
+} |
+ |
+std::list<std::unique_ptr<TraceLog::TraceEventFilter>>* GetCategoryGroupFilter( |
+ const unsigned char* category_group_enabled) { |
+ return g_category_group_filter[GetCategoryIndex(category_group_enabled)] |
+ .Pointer(); |
} |
void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) { |
@@ -485,6 +530,31 @@ void TraceLog::UpdateCategoryGroupEnabledFlag(size_t category_index) { |
if (mode_ == RECORDING_MODE && !strcmp(category_group, "__metadata")) |
enabled_flag |= ENABLED_FOR_RECORDING; |
+ // Having a filter is an exceptional case, so we avoid |
+ // the LazyInstance creation in the common case. |
+ if (!(g_category_group_filter[category_index] == nullptr)) |
+ g_category_group_filter[category_index].Get().clear(); |
+ |
+ for (const auto& event_filter : trace_config_.event_filters()) { |
+ if (event_filter.IsCategoryGroupEnabled(category_group)) { |
+ std::unique_ptr<TraceEventFilter> new_filter; |
+ |
+ if (event_filter.predicate_name() == "event_whitelist_predicate") { |
+ new_filter = |
+ WrapUnique(new EventNameFilter(event_filter.filter_args())); |
+ } else if (event_filter.predicate_name() == "testing_predicate") { |
+ CHECK(g_trace_event_filter_constructor_for_testing); |
+ new_filter = g_trace_event_filter_constructor_for_testing(); |
+ } |
+ |
+ if (new_filter) { |
+ g_category_group_filter[category_index].Get().push_back( |
+ std::move(new_filter)); |
+ enabled_flag |= ENABLED_FOR_FILTERING; |
+ } |
+ } |
+ } |
+ |
g_category_group_enabled[category_index] = enabled_flag; |
} |
@@ -1271,7 +1341,32 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp( |
#endif // OS_WIN |
std::string console_message; |
- if (*category_group_enabled & ENABLED_FOR_RECORDING) { |
+ std::unique_ptr<TraceEvent> filtered_trace_event; |
+ if (*category_group_enabled & ENABLED_FOR_FILTERING) { |
+ std::unique_ptr<TraceEvent> new_trace_event(new TraceEvent); |
+ new_trace_event->Initialize(thread_id, offset_event_timestamp, thread_now, |
+ phase, category_group_enabled, name, scope, id, |
+ bind_id, num_args, arg_names, arg_types, |
+ arg_values, convertable_values, flags); |
+ |
+ auto filter_list = GetCategoryGroupFilter(category_group_enabled); |
+ DCHECK(!filter_list->empty()); |
+ |
+ bool should_add_event = false; |
+ for (const auto& trace_event_filter : *filter_list) { |
+ if (trace_event_filter->FilterTraceEvent(*new_trace_event)) |
+ should_add_event = true; |
+ } |
+ |
+ if (should_add_event) |
+ filtered_trace_event = std::move(new_trace_event); |
+ } |
+ |
+ // Add the trace event if we're either *just* recording (and not filtering) |
+ // or if we one of our filters indicates the event should be added. |
+ if (((*category_group_enabled & ENABLED_FOR_RECORDING) && |
+ (*category_group_enabled & ENABLED_FOR_FILTERING) == 0) || |
+ filtered_trace_event) { |
OptionalAutoLock lock(&lock_); |
TraceEvent* trace_event = NULL; |
@@ -1283,21 +1378,14 @@ TraceEventHandle TraceLog::AddTraceEventWithThreadIdAndTimestamp( |
} |
if (trace_event) { |
- trace_event->Initialize(thread_id, |
- offset_event_timestamp, |
- thread_now, |
- phase, |
- category_group_enabled, |
- name, |
- scope, |
- id, |
- bind_id, |
- num_args, |
- arg_names, |
- arg_types, |
- arg_values, |
- convertable_values, |
- flags); |
+ if (filtered_trace_event) { |
+ trace_event->MoveFrom(std::move(filtered_trace_event)); |
+ } else { |
+ trace_event->Initialize(thread_id, offset_event_timestamp, thread_now, |
+ phase, category_group_enabled, name, scope, id, |
+ bind_id, num_args, arg_names, arg_types, |
+ arg_values, convertable_values, flags); |
+ } |
#if defined(OS_ANDROID) |
trace_event->SendToATrace(); |
@@ -1435,6 +1523,18 @@ std::string TraceLog::EventToConsoleMessage(unsigned char phase, |
return log.str(); |
} |
+void TraceLog::EndFilteredEvent(const unsigned char* category_group_enabled, |
+ const char* name, |
+ TraceEventHandle handle) { |
+ auto filter_list = GetCategoryGroupFilter(category_group_enabled); |
+ DCHECK(!filter_list->empty()); |
+ |
+ for (const auto& trace_event_filter : *filter_list) { |
+ trace_event_filter->EndEvent(name, |
+ GetCategoryGroupName(category_group_enabled)); |
+ } |
+} |
+ |
void TraceLog::UpdateTraceEventDuration( |
const unsigned char* category_group_enabled, |
const char* name, |
@@ -1599,6 +1699,11 @@ void TraceLog::DeleteForTesting() { |
internal::DeleteTraceLogForTesting::Delete(); |
} |
+void TraceLog::SetTraceEventFilterConstructorForTesting( |
+ TraceEventFilterConstructorForTesting predicate) { |
+ g_trace_event_filter_constructor_for_testing = predicate; |
+} |
+ |
TraceEvent* TraceLog::GetEventByHandle(TraceEventHandle handle) { |
return GetEventByHandleInternal(handle, NULL); |
} |