OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/trace_event/trace_event_impl.h" | 5 #include "base/trace_event/trace_event_impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/base_switches.h" | 9 #include "base/base_switches.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
59 // trace. | 59 // trace. |
60 const int kOverheadReportThresholdInMicroseconds = 50; | 60 const int kOverheadReportThresholdInMicroseconds = 50; |
61 | 61 |
62 // String options that can be used to initialize TraceOptions. | 62 // String options that can be used to initialize TraceOptions. |
63 const char kRecordUntilFull[] = "record-until-full"; | 63 const char kRecordUntilFull[] = "record-until-full"; |
64 const char kRecordContinuously[] = "record-continuously"; | 64 const char kRecordContinuously[] = "record-continuously"; |
65 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible"; | 65 const char kRecordAsMuchAsPossible[] = "record-as-much-as-possible"; |
66 const char kTraceToConsole[] = "trace-to-console"; | 66 const char kTraceToConsole[] = "trace-to-console"; |
67 const char kEnableSampling[] = "enable-sampling"; | 67 const char kEnableSampling[] = "enable-sampling"; |
68 const char kEnableSystrace[] = "enable-systrace"; | 68 const char kEnableSystrace[] = "enable-systrace"; |
| 69 const char kEnableArgsWhitelist[] = "enable-args-whitelist"; |
69 | 70 |
70 // Controls the number of trace events we will buffer in-memory | 71 // Controls the number of trace events we will buffer in-memory |
71 // before throwing them away. | 72 // before throwing them away. |
72 const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize; | 73 const size_t kTraceBufferChunkSize = TraceBufferChunk::kTraceBufferChunkSize; |
73 const size_t kTraceEventVectorBigBufferChunks = | 74 const size_t kTraceEventVectorBigBufferChunks = |
74 512000000 / kTraceBufferChunkSize; | 75 512000000 / kTraceBufferChunkSize; |
75 const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize; | 76 const size_t kTraceEventVectorBufferChunks = 256000 / kTraceBufferChunkSize; |
76 const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4; | 77 const size_t kTraceEventRingBufferChunks = kTraceEventVectorBufferChunks / 4; |
77 const size_t kTraceEventBufferSizeInBytes = 100 * 1024; | 78 const size_t kTraceEventBufferSizeInBytes = 100 * 1024; |
78 // Can store results for 30 seconds with 1 ms sampling interval. | 79 // Can store results for 30 seconds with 1 ms sampling interval. |
(...skipping 607 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
686 case TRACE_VALUE_TYPE_STRING: | 687 case TRACE_VALUE_TYPE_STRING: |
687 case TRACE_VALUE_TYPE_COPY_STRING: | 688 case TRACE_VALUE_TYPE_COPY_STRING: |
688 EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out); | 689 EscapeJSONString(value.as_string ? value.as_string : "NULL", true, out); |
689 break; | 690 break; |
690 default: | 691 default: |
691 NOTREACHED() << "Don't know how to print this value"; | 692 NOTREACHED() << "Don't know how to print this value"; |
692 break; | 693 break; |
693 } | 694 } |
694 } | 695 } |
695 | 696 |
696 void TraceEvent::AppendAsJSON(std::string* out) const { | 697 bool TraceEvent::IsPIIWhitelisted() const { |
| 698 const char* category_group_name = |
| 699 TraceLog::GetCategoryGroupName(category_group_enabled_); |
| 700 CStringTokenizer category_group_tokens( |
| 701 category_group_name, category_group_name + strlen(category_group_name), |
| 702 ","); |
| 703 while (category_group_tokens.GetNext()) { |
| 704 const std::string& category_group_token = category_group_tokens.token(); |
| 705 for (int i = 0; kEventArgsWhitelist[i][0] != NULL; ++i) { |
| 706 DCHECK(kEventArgsWhitelist[i][1]); |
| 707 |
| 708 if (MatchPattern(category_group_token.c_str(), |
| 709 kEventArgsWhitelist[i][0]) && |
| 710 MatchPattern(name_, kEventArgsWhitelist[i][1])) { |
| 711 return true; |
| 712 } |
| 713 } |
| 714 } |
| 715 |
| 716 return false; |
| 717 } |
| 718 |
| 719 void TraceEvent::AppendAsJSON(std::string* out, |
| 720 bool enable_args_whitelist) const { |
697 int64 time_int64 = timestamp_.ToInternalValue(); | 721 int64 time_int64 = timestamp_.ToInternalValue(); |
698 int process_id = TraceLog::GetInstance()->process_id(); | 722 int process_id = TraceLog::GetInstance()->process_id(); |
699 // Category group checked at category creation time. | 723 // Category group checked at category creation time. |
700 DCHECK(!strchr(name_, '"')); | 724 DCHECK(!strchr(name_, '"')); |
701 StringAppendF(out, | 725 StringAppendF(out, |
702 "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 "," | 726 "{\"pid\":%i,\"tid\":%i,\"ts\":%" PRId64 "," |
703 "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":{", | 727 "\"ph\":\"%c\",\"cat\":\"%s\",\"name\":\"%s\",\"args\":{", |
704 process_id, | 728 process_id, |
705 thread_id_, | 729 thread_id_, |
706 time_int64, | 730 time_int64, |
707 phase_, | 731 phase_, |
708 TraceLog::GetCategoryGroupName(category_group_enabled_), | 732 TraceLog::GetCategoryGroupName(category_group_enabled_), |
709 name_); | 733 name_); |
710 | 734 |
711 // Output argument names and values, stop at first NULL argument name. | 735 // Output argument names and values, stop at first NULL argument name. |
712 for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { | 736 if (arg_names_[0]) { |
713 if (i > 0) | 737 bool allow_args = !enable_args_whitelist || IsPIIWhitelisted(); |
714 *out += ","; | |
715 *out += "\""; | |
716 *out += arg_names_[i]; | |
717 *out += "\":"; | |
718 | 738 |
719 if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) | 739 if (allow_args) { |
720 convertable_values_[i]->AppendAsTraceFormat(out); | 740 for (int i = 0; i < kTraceMaxNumArgs && arg_names_[i]; ++i) { |
721 else | 741 if (i > 0) |
722 AppendValueAsJSON(arg_types_[i], arg_values_[i], out); | 742 *out += ","; |
| 743 *out += "\""; |
| 744 *out += arg_names_[i]; |
| 745 *out += "\":"; |
| 746 |
| 747 if (arg_types_[i] == TRACE_VALUE_TYPE_CONVERTABLE) |
| 748 convertable_values_[i]->AppendAsTraceFormat(out); |
| 749 else |
| 750 AppendValueAsJSON(arg_types_[i], arg_values_[i], out); |
| 751 } |
| 752 } else { |
| 753 *out += "\"stripped\":1"; |
| 754 } |
723 } | 755 } |
| 756 |
724 *out += "}"; | 757 *out += "}"; |
725 | 758 |
726 if (phase_ == TRACE_EVENT_PHASE_COMPLETE) { | 759 if (phase_ == TRACE_EVENT_PHASE_COMPLETE) { |
727 int64 duration = duration_.ToInternalValue(); | 760 int64 duration = duration_.ToInternalValue(); |
728 if (duration != -1) | 761 if (duration != -1) |
729 StringAppendF(out, ",\"dur\":%" PRId64, duration); | 762 StringAppendF(out, ",\"dur\":%" PRId64, duration); |
730 if (!thread_timestamp_.is_null()) { | 763 if (!thread_timestamp_.is_null()) { |
731 int64 thread_duration = thread_duration_.ToInternalValue(); | 764 int64 thread_duration = thread_duration_.ToInternalValue(); |
732 if (thread_duration != -1) | 765 if (thread_duration != -1) |
733 StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration); | 766 StringAppendF(out, ",\"tdur\":%" PRId64, thread_duration); |
(...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
989 } else if (*iter == kRecordContinuously) { | 1022 } else if (*iter == kRecordContinuously) { |
990 record_mode = RECORD_CONTINUOUSLY; | 1023 record_mode = RECORD_CONTINUOUSLY; |
991 } else if (*iter == kTraceToConsole) { | 1024 } else if (*iter == kTraceToConsole) { |
992 record_mode = ECHO_TO_CONSOLE; | 1025 record_mode = ECHO_TO_CONSOLE; |
993 } else if (*iter == kRecordAsMuchAsPossible) { | 1026 } else if (*iter == kRecordAsMuchAsPossible) { |
994 record_mode = RECORD_AS_MUCH_AS_POSSIBLE; | 1027 record_mode = RECORD_AS_MUCH_AS_POSSIBLE; |
995 } else if (*iter == kEnableSampling) { | 1028 } else if (*iter == kEnableSampling) { |
996 enable_sampling = true; | 1029 enable_sampling = true; |
997 } else if (*iter == kEnableSystrace) { | 1030 } else if (*iter == kEnableSystrace) { |
998 enable_systrace = true; | 1031 enable_systrace = true; |
| 1032 } else if (*iter == kEnableArgsWhitelist) { |
| 1033 enable_args_whitelist = true; |
999 } else { | 1034 } else { |
1000 return false; | 1035 return false; |
1001 } | 1036 } |
1002 } | 1037 } |
1003 return true; | 1038 return true; |
1004 } | 1039 } |
1005 | 1040 |
1006 std::string TraceOptions::ToString() const { | 1041 std::string TraceOptions::ToString() const { |
1007 std::string ret; | 1042 std::string ret; |
1008 switch (record_mode) { | 1043 switch (record_mode) { |
1009 case RECORD_UNTIL_FULL: | 1044 case RECORD_UNTIL_FULL: |
1010 ret = kRecordUntilFull; | 1045 ret = kRecordUntilFull; |
1011 break; | 1046 break; |
1012 case RECORD_CONTINUOUSLY: | 1047 case RECORD_CONTINUOUSLY: |
1013 ret = kRecordContinuously; | 1048 ret = kRecordContinuously; |
1014 break; | 1049 break; |
1015 case ECHO_TO_CONSOLE: | 1050 case ECHO_TO_CONSOLE: |
1016 ret = kTraceToConsole; | 1051 ret = kTraceToConsole; |
1017 break; | 1052 break; |
1018 case RECORD_AS_MUCH_AS_POSSIBLE: | 1053 case RECORD_AS_MUCH_AS_POSSIBLE: |
1019 ret = kRecordAsMuchAsPossible; | 1054 ret = kRecordAsMuchAsPossible; |
1020 break; | 1055 break; |
1021 default: | 1056 default: |
1022 NOTREACHED(); | 1057 NOTREACHED(); |
1023 } | 1058 } |
1024 if (enable_sampling) | 1059 if (enable_sampling) |
1025 ret = ret + "," + kEnableSampling; | 1060 ret = ret + "," + kEnableSampling; |
1026 if (enable_systrace) | 1061 if (enable_systrace) |
1027 ret = ret + "," + kEnableSystrace; | 1062 ret = ret + "," + kEnableSystrace; |
| 1063 if (enable_args_whitelist) |
| 1064 ret = ret + "," + kEnableArgsWhitelist; |
1028 return ret; | 1065 return ret; |
1029 } | 1066 } |
1030 | 1067 |
1031 //////////////////////////////////////////////////////////////////////////////// | 1068 //////////////////////////////////////////////////////////////////////////////// |
1032 // | 1069 // |
1033 // TraceLog | 1070 // TraceLog |
1034 // | 1071 // |
1035 //////////////////////////////////////////////////////////////////////////////// | 1072 //////////////////////////////////////////////////////////////////////////////// |
1036 | 1073 |
1037 class TraceLog::ThreadLocalEventBuffer | 1074 class TraceLog::ThreadLocalEventBuffer |
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1471 { | 1508 { |
1472 AutoLock lock(lock_); | 1509 AutoLock lock(lock_); |
1473 dispatching_to_observer_list_ = false; | 1510 dispatching_to_observer_list_ = false; |
1474 } | 1511 } |
1475 } | 1512 } |
1476 | 1513 |
1477 TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceOptions( | 1514 TraceLog::InternalTraceOptions TraceLog::GetInternalOptionsFromTraceOptions( |
1478 const TraceOptions& options) { | 1515 const TraceOptions& options) { |
1479 InternalTraceOptions ret = | 1516 InternalTraceOptions ret = |
1480 options.enable_sampling ? kInternalEnableSampling : kInternalNone; | 1517 options.enable_sampling ? kInternalEnableSampling : kInternalNone; |
| 1518 if (options.enable_args_whitelist) |
| 1519 ret |= kInternalEnableArgsWhitelist; |
1481 switch (options.record_mode) { | 1520 switch (options.record_mode) { |
1482 case RECORD_UNTIL_FULL: | 1521 case RECORD_UNTIL_FULL: |
1483 return ret | kInternalRecordUntilFull; | 1522 return ret | kInternalRecordUntilFull; |
1484 case RECORD_CONTINUOUSLY: | 1523 case RECORD_CONTINUOUSLY: |
1485 return ret | kInternalRecordContinuously; | 1524 return ret | kInternalRecordContinuously; |
1486 case ECHO_TO_CONSOLE: | 1525 case ECHO_TO_CONSOLE: |
1487 return ret | kInternalEchoToConsole; | 1526 return ret | kInternalEchoToConsole; |
1488 case RECORD_AS_MUCH_AS_POSSIBLE: | 1527 case RECORD_AS_MUCH_AS_POSSIBLE: |
1489 return ret | kInternalRecordAsMuchAsPossible; | 1528 return ret | kInternalRecordAsMuchAsPossible; |
1490 } | 1529 } |
1491 NOTREACHED(); | 1530 NOTREACHED(); |
1492 return kInternalNone; | 1531 return kInternalNone; |
1493 } | 1532 } |
1494 | 1533 |
1495 CategoryFilter TraceLog::GetCurrentCategoryFilter() { | 1534 CategoryFilter TraceLog::GetCurrentCategoryFilter() { |
1496 AutoLock lock(lock_); | 1535 AutoLock lock(lock_); |
1497 return category_filter_; | 1536 return category_filter_; |
1498 } | 1537 } |
1499 | 1538 |
1500 TraceOptions TraceLog::GetCurrentTraceOptions() const { | 1539 TraceOptions TraceLog::GetCurrentTraceOptions() const { |
1501 TraceOptions ret; | 1540 TraceOptions ret; |
1502 InternalTraceOptions option = trace_options(); | 1541 InternalTraceOptions option = trace_options(); |
1503 ret.enable_sampling = (option & kInternalEnableSampling) != 0; | 1542 ret.enable_sampling = (option & kInternalEnableSampling) != 0; |
| 1543 ret.enable_args_whitelist = (option & kInternalEnableArgsWhitelist) != 0; |
1504 if (option & kInternalRecordUntilFull) | 1544 if (option & kInternalRecordUntilFull) |
1505 ret.record_mode = RECORD_UNTIL_FULL; | 1545 ret.record_mode = RECORD_UNTIL_FULL; |
1506 else if (option & kInternalRecordContinuously) | 1546 else if (option & kInternalRecordContinuously) |
1507 ret.record_mode = RECORD_CONTINUOUSLY; | 1547 ret.record_mode = RECORD_CONTINUOUSLY; |
1508 else if (option & kInternalEchoToConsole) | 1548 else if (option & kInternalEchoToConsole) |
1509 ret.record_mode = ECHO_TO_CONSOLE; | 1549 ret.record_mode = ECHO_TO_CONSOLE; |
1510 else if (option & kInternalRecordAsMuchAsPossible) | 1550 else if (option & kInternalRecordAsMuchAsPossible) |
1511 ret.record_mode = RECORD_AS_MUCH_AS_POSSIBLE; | 1551 ret.record_mode = RECORD_AS_MUCH_AS_POSSIBLE; |
1512 else | 1552 else |
1513 NOTREACHED(); | 1553 NOTREACHED(); |
(...skipping 226 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1740 } | 1780 } |
1741 | 1781 |
1742 // Usually it runs on a different thread. | 1782 // Usually it runs on a different thread. |
1743 void TraceLog::ConvertTraceEventsToTraceFormat( | 1783 void TraceLog::ConvertTraceEventsToTraceFormat( |
1744 scoped_ptr<TraceBuffer> logged_events, | 1784 scoped_ptr<TraceBuffer> logged_events, |
1745 const TraceLog::OutputCallback& flush_output_callback) { | 1785 const TraceLog::OutputCallback& flush_output_callback) { |
1746 | 1786 |
1747 if (flush_output_callback.is_null()) | 1787 if (flush_output_callback.is_null()) |
1748 return; | 1788 return; |
1749 | 1789 |
| 1790 InternalTraceOptions options = trace_options(); |
| 1791 bool enable_args_whitelist = (options & kInternalEnableArgsWhitelist) != 0; |
1750 // The callback need to be called at least once even if there is no events | 1792 // The callback need to be called at least once even if there is no events |
1751 // to let the caller know the completion of flush. | 1793 // to let the caller know the completion of flush. |
1752 bool has_more_events = true; | 1794 bool has_more_events = true; |
1753 do { | 1795 do { |
1754 scoped_refptr<RefCountedString> json_events_str_ptr = | 1796 scoped_refptr<RefCountedString> json_events_str_ptr = |
1755 new RefCountedString(); | 1797 new RefCountedString(); |
1756 | 1798 |
1757 while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) { | 1799 while (json_events_str_ptr->size() < kTraceEventBufferSizeInBytes) { |
1758 const TraceBufferChunk* chunk = logged_events->NextChunk(); | 1800 const TraceBufferChunk* chunk = logged_events->NextChunk(); |
1759 has_more_events = chunk != NULL; | 1801 has_more_events = chunk != NULL; |
1760 if (!chunk) | 1802 if (!chunk) |
1761 break; | 1803 break; |
1762 for (size_t j = 0; j < chunk->size(); ++j) { | 1804 for (size_t j = 0; j < chunk->size(); ++j) { |
1763 if (json_events_str_ptr->size()) | 1805 if (json_events_str_ptr->size()) |
1764 json_events_str_ptr->data().append(",\n"); | 1806 json_events_str_ptr->data().append(",\n"); |
1765 chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data())); | 1807 chunk->GetEventAt(j)->AppendAsJSON(&(json_events_str_ptr->data()), |
| 1808 enable_args_whitelist); |
1766 } | 1809 } |
1767 } | 1810 } |
1768 flush_output_callback.Run(json_events_str_ptr, has_more_events); | 1811 flush_output_callback.Run(json_events_str_ptr, has_more_events); |
1769 } while (has_more_events); | 1812 } while (has_more_events); |
1770 } | 1813 } |
1771 | 1814 |
1772 void TraceLog::FinishFlush(int generation) { | 1815 void TraceLog::FinishFlush(int generation) { |
1773 scoped_ptr<TraceBuffer> previous_logged_events; | 1816 scoped_ptr<TraceBuffer> previous_logged_events; |
1774 OutputCallback flush_output_callback; | 1817 OutputCallback flush_output_callback; |
1775 | 1818 |
1776 if (!CheckGeneration(generation)) | 1819 if (!CheckGeneration(generation)) |
1777 return; | 1820 return; |
1778 | 1821 |
1779 { | 1822 { |
1780 AutoLock lock(lock_); | 1823 AutoLock lock(lock_); |
1781 | 1824 |
1782 previous_logged_events.swap(logged_events_); | 1825 previous_logged_events.swap(logged_events_); |
1783 UseNextTraceBuffer(); | 1826 UseNextTraceBuffer(); |
1784 thread_message_loops_.clear(); | 1827 thread_message_loops_.clear(); |
1785 | 1828 |
1786 flush_message_loop_proxy_ = NULL; | 1829 flush_message_loop_proxy_ = NULL; |
1787 flush_output_callback = flush_output_callback_; | 1830 flush_output_callback = flush_output_callback_; |
1788 flush_output_callback_.Reset(); | 1831 flush_output_callback_.Reset(); |
1789 } | 1832 } |
1790 | 1833 |
1791 if (use_worker_thread_ && | 1834 if (use_worker_thread_ && |
1792 WorkerPool::PostTask( | 1835 WorkerPool::PostTask( |
1793 FROM_HERE, | 1836 FROM_HERE, |
1794 Bind(&TraceLog::ConvertTraceEventsToTraceFormat, | 1837 Bind(&TraceLog::ConvertTraceEventsToTraceFormat, Unretained(this), |
1795 Passed(&previous_logged_events), | 1838 Passed(&previous_logged_events), flush_output_callback), |
1796 flush_output_callback), | |
1797 true)) { | 1839 true)) { |
1798 return; | 1840 return; |
1799 } | 1841 } |
1800 | 1842 |
1801 ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(), | 1843 ConvertTraceEventsToTraceFormat(previous_logged_events.Pass(), |
1802 flush_output_callback); | 1844 flush_output_callback); |
1803 } | 1845 } |
1804 | 1846 |
1805 // Run in each thread holding a local event buffer. | 1847 // Run in each thread holding a local event buffer. |
1806 void TraceLog::FlushCurrentThread(int generation) { | 1848 void TraceLog::FlushCurrentThread(int generation) { |
(...skipping 808 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2615 } | 2657 } |
2616 | 2658 |
2617 ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() { | 2659 ScopedTraceBinaryEfficient::~ScopedTraceBinaryEfficient() { |
2618 if (*category_group_enabled_) { | 2660 if (*category_group_enabled_) { |
2619 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, | 2661 TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_group_enabled_, |
2620 name_, event_handle_); | 2662 name_, event_handle_); |
2621 } | 2663 } |
2622 } | 2664 } |
2623 | 2665 |
2624 } // namespace trace_event_internal | 2666 } // namespace trace_event_internal |
OLD | NEW |