| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009 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 "net/base/net_log_util.h" | |
| 6 | |
| 7 #include "base/format_macros.h" | |
| 8 #include "base/json/json_writer.h" | |
| 9 #include "base/string_util.h" | |
| 10 #include "base/values.h" | |
| 11 #include "net/base/net_errors.h" | |
| 12 | |
| 13 namespace net { | |
| 14 namespace { | |
| 15 | |
| 16 class FormatHelper { | |
| 17 public: | |
| 18 std::string ToString(const std::vector<CapturingNetLog::Entry>& entries, | |
| 19 size_t num_entries_truncated) { | |
| 20 entries_.clear(); | |
| 21 | |
| 22 // Pass 1: Match the start/end of indentation blocks. Fills |entries_| | |
| 23 // with the results. | |
| 24 PopulateEntries(entries); | |
| 25 | |
| 26 // Pass 2: Figure out the maximum width of each column. This allows us | |
| 27 // to right-justify text within each column. | |
| 28 size_t max_time_width, max_indentation, max_type_width, max_dt_width; | |
| 29 GetMaxExtent( | |
| 30 &max_time_width, &max_indentation, &max_type_width, &max_dt_width); | |
| 31 | |
| 32 // Pass 3: Assemble the string. | |
| 33 std::string result; | |
| 34 | |
| 35 const int kSpacesPerIndentation = 2; | |
| 36 | |
| 37 for (size_t i = 0; i < entries_.size(); ++i) { | |
| 38 if (num_entries_truncated > 0 && i + 1 == entries_.size()) { | |
| 39 StringAppendF(&result, " ... Truncated %" PRIuS " entries ...\n", | |
| 40 num_entries_truncated); | |
| 41 } | |
| 42 | |
| 43 if (entries_[i].block_index != -1 && | |
| 44 static_cast<size_t>(entries_[i].block_index + 1) == i) { | |
| 45 // If there were no entries in between the START/END block then don't | |
| 46 // bother printing a line for END (it just adds noise, and we already | |
| 47 // show the time delta besides START anyway). | |
| 48 continue; | |
| 49 } | |
| 50 | |
| 51 int indentation_spaces = entries_[i].indentation * kSpacesPerIndentation; | |
| 52 std::string entry_str = GetEntryString(i); | |
| 53 | |
| 54 StringAppendF(&result, "t=%s: %s%s", | |
| 55 PadStringLeft(GetTimeString(i), max_time_width).c_str(), | |
| 56 PadStringLeft("", indentation_spaces).c_str(), | |
| 57 entry_str.c_str()); | |
| 58 | |
| 59 if (entries_[i].IsBeginEvent()) { | |
| 60 // Summarize how long this block lasted. | |
| 61 int padding = ((max_indentation - entries_[i].indentation) * | |
| 62 kSpacesPerIndentation) + (max_type_width - entry_str.size()); | |
| 63 StringAppendF(&result, "%s [dt=%s]", | |
| 64 PadStringLeft("", padding).c_str(), | |
| 65 PadStringLeft(GetBlockDtString(i), max_dt_width).c_str()); | |
| 66 } | |
| 67 | |
| 68 // Append any custom parameters. | |
| 69 NetLog::EventParameters* extra_params = | |
| 70 entries_[i].log_entry->extra_parameters; | |
| 71 | |
| 72 if (extra_params) { | |
| 73 std::string extra_details; | |
| 74 scoped_ptr<Value> extra_details_value(extra_params->ToValue()); | |
| 75 base::JSONWriter::Write(extra_details_value.get(), true, | |
| 76 &extra_details); | |
| 77 // JSON writer uses CR LF in its pretty-printer. Normalize to newlines. | |
| 78 ReplaceSubstringsAfterOffset(&extra_details, 0, "\r\n", "\n"); | |
| 79 result.append("\n"); | |
| 80 result.append(extra_details); | |
| 81 } | |
| 82 | |
| 83 if (!extra_params && i + 1 != entries_.size()) | |
| 84 result += "\n"; | |
| 85 } | |
| 86 | |
| 87 return result; | |
| 88 } | |
| 89 | |
| 90 private: | |
| 91 struct Entry { | |
| 92 explicit Entry(const CapturingNetLog::Entry* log_entry) | |
| 93 : log_entry(log_entry), indentation(0), block_index(-1) {} | |
| 94 | |
| 95 bool IsBeginEvent() const { | |
| 96 return log_entry->phase == NetLog::PHASE_BEGIN; | |
| 97 } | |
| 98 | |
| 99 bool IsEndEvent() const { | |
| 100 return log_entry->phase == NetLog::PHASE_END; | |
| 101 } | |
| 102 | |
| 103 const CapturingNetLog::Entry* log_entry; | |
| 104 size_t indentation; | |
| 105 int block_index; // The index of the matching start / end of block. | |
| 106 }; | |
| 107 | |
| 108 void PopulateEntries(const std::vector<CapturingNetLog::Entry>& entries) { | |
| 109 int current_indentation = 0; | |
| 110 | |
| 111 for (size_t i = 0; i < entries.size(); ++i) { | |
| 112 Entry entry(&entries[i]); | |
| 113 | |
| 114 entry.indentation = current_indentation; | |
| 115 | |
| 116 if (entry.IsBeginEvent()) { | |
| 117 // Indent everything contained in this block. | |
| 118 current_indentation++; | |
| 119 } | |
| 120 | |
| 121 if (entry.IsEndEvent()) { | |
| 122 int start_index = FindStartOfBlockIndex(entry); | |
| 123 if (start_index != -1) { | |
| 124 // Point the start / end of block at each other. | |
| 125 entry.block_index = start_index; | |
| 126 entries_[start_index].block_index = i; | |
| 127 | |
| 128 // Restore the indentation prior to the block. | |
| 129 // (Could be more than 1 level if close of blocks are missing). | |
| 130 current_indentation = entries_[start_index].indentation; | |
| 131 entry.indentation = current_indentation; | |
| 132 } | |
| 133 } | |
| 134 | |
| 135 entries_.push_back(entry); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 int FindStartOfBlockIndex(const Entry& entry) { | |
| 140 DCHECK(entry.IsEndEvent()); | |
| 141 | |
| 142 // Find the matching start of block by scanning backwards. | |
| 143 for (int i = entries_.size() - 1; i >= 0; --i) { | |
| 144 if (entries_[i].IsBeginEvent() && | |
| 145 entries_[i].log_entry->type == entry.log_entry->type) { | |
| 146 return i; | |
| 147 } | |
| 148 } | |
| 149 return -1; // Start not found. | |
| 150 } | |
| 151 | |
| 152 void GetMaxExtent(size_t* max_time_width, | |
| 153 size_t* max_indentation, | |
| 154 size_t* max_type_width, | |
| 155 size_t* max_dt_width) { | |
| 156 *max_time_width = *max_indentation = *max_type_width = *max_dt_width = 0; | |
| 157 for (size_t i = 0; i < entries_.size(); ++i) { | |
| 158 *max_time_width = std::max(*max_time_width, GetTimeString(i).size()); | |
| 159 if (entries_[i].log_entry->phase != NetLog::PHASE_NONE) | |
| 160 *max_type_width = std::max(*max_type_width, GetEntryString(i).size()); | |
| 161 *max_indentation = std::max(*max_indentation, entries_[i].indentation); | |
| 162 | |
| 163 if (entries_[i].IsBeginEvent()) | |
| 164 *max_dt_width = std::max(*max_dt_width, GetBlockDtString(i).size()); | |
| 165 } | |
| 166 } | |
| 167 | |
| 168 std::string GetBlockDtString(size_t start_index) { | |
| 169 int end_index = entries_[start_index].block_index; | |
| 170 if (end_index == -1) { | |
| 171 // Block is not closed, implicitly close it at EOF. | |
| 172 end_index = entries_.size() - 1; | |
| 173 } | |
| 174 int64 dt_ms = (entries_[end_index].log_entry->time - | |
| 175 entries_[start_index].log_entry->time).InMilliseconds(); | |
| 176 | |
| 177 return Int64ToString(dt_ms); | |
| 178 } | |
| 179 | |
| 180 std::string GetTimeString(size_t index) { | |
| 181 int64 t_ms = (entries_[index].log_entry->time - | |
| 182 base::TimeTicks()).InMilliseconds(); | |
| 183 return Int64ToString(t_ms); | |
| 184 } | |
| 185 | |
| 186 std::string GetEntryString(size_t index) { | |
| 187 const CapturingNetLog::Entry* entry = entries_[index].log_entry; | |
| 188 | |
| 189 std::string entry_str; | |
| 190 NetLog::EventPhase phase = entry->phase; | |
| 191 | |
| 192 entry_str = NetLog::EventTypeToString(entry->type); | |
| 193 | |
| 194 if (phase == NetLog::PHASE_BEGIN && | |
| 195 index + 1 < entries_.size() && | |
| 196 static_cast<size_t>(entries_[index + 1].block_index) == index) { | |
| 197 // If this starts an empty block, we will pretend it is a PHASE_NONE | |
| 198 // so we don't print the "+" prefix. | |
| 199 phase = NetLog::PHASE_NONE; | |
| 200 } | |
| 201 | |
| 202 switch (phase) { | |
| 203 case NetLog::PHASE_BEGIN: | |
| 204 return std::string("+") + entry_str; | |
| 205 case NetLog::PHASE_END: | |
| 206 return std::string("-") + entry_str; | |
| 207 case NetLog::PHASE_NONE: | |
| 208 return std::string(" ") + entry_str; | |
| 209 default: | |
| 210 NOTREACHED(); | |
| 211 return std::string(); | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 static std::string PadStringLeft(const std::string& str, size_t width) { | |
| 216 DCHECK_LE(str.size(), width); | |
| 217 std::string padding; | |
| 218 padding.resize(width - str.size(), ' '); | |
| 219 return padding + str; | |
| 220 } | |
| 221 | |
| 222 std::vector<Entry> entries_; | |
| 223 }; | |
| 224 | |
| 225 } // namespace | |
| 226 | |
| 227 // static | |
| 228 std::string NetLogUtil::PrettyPrintAsEventTree( | |
| 229 const std::vector<CapturingNetLog::Entry>& entries, | |
| 230 size_t num_entries_truncated) { | |
| 231 FormatHelper helper; | |
| 232 return helper.ToString(entries, num_entries_truncated); | |
| 233 } | |
| 234 | |
| 235 } // namespace net | |
| OLD | NEW |