1 // Copyright (c) 2011 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 #ifndef CHROME_BROWSER_NET_PASSIVE_LOG_COLLECTOR_H_ 6 #define CHROME_BROWSER_NET_PASSIVE_LOG_COLLECTOR_H_ 7 #pragma once 8 9 #include <deque> 10 #include <string> 11 #include <vector> 12 13 #include "base/gtest_prod_util.h" 14 #include "base/hash_tables.h" 15 #include "base/memory/ref_counted.h" 16 #include "base/time.h" 17 #include "chrome/browser/net/chrome_net_log.h" 18 #include "net/base/net_log.h" 19 20 // PassiveLogCollector watches the NetLog event stream, and saves the network 21 // events for recent requests, in a circular buffer. 22 // 23 // This is done so that when a network problem is encountered (performance 24 // problem, or error), about:net-internals can be opened shortly after the 25 // problem and it will contain a trace for the problem request. 26 // 27 // (This is in contrast to the "active logging" which captures every single 28 // network event, but requires capturing to have been enabled *prior* to 29 // encountering the problem. Active capturing is enabled as long as 30 // about:net-internals is open). 31 // 32 // The data captured by PassiveLogCollector is grouped by NetLog::Source, into 33 // a SourceInfo structure. These in turn are grouped by NetLog::SourceType, and 34 // owned by a SourceTracker instance for the specific source type. 35 // 36 // The PassiveLogCollector is owned by the ChromeNetLog itself, and is not 37 // thread safe. The ChromeNetLog is responsible for calling it in a thread safe 38 // manner. 39 class PassiveLogCollector : public ChromeNetLog::ThreadSafeObserver { 40 public: 41 typedef std::vector<net::NetLog::Source> SourceDependencyList; 42 43 struct SourceInfo { 44 SourceInfo(); 45 ~SourceInfo(); 46 47 // Returns the URL that corresponds with this source. This is 48 // only meaningful for certain source types (URL_REQUEST, SOCKET_STREAM). 49 // For the rest, it will return an empty string. 50 std::string GetURL() const; 51 52 uint32 source_id; 53 ChromeNetLog::EntryList entries; 54 size_t num_entries_truncated; 55 56 // List of other sources which contain information relevant to this 57 // source (for example, a url request might depend on the log items 58 // for a connect job and for a socket that were bound to it.) 59 SourceDependencyList dependencies; 60 61 // Holds the count of how many other sources have added this as a 62 // dependent source. When it is 0, it means noone has referenced it so it 63 // can be deleted normally. 64 int reference_count; 65 66 // |is_alive| is set to false once the source has been added to the 67 // tracker's graveyard (it may still be kept around due to a non-zero 68 // reference_count, but it is still considered "dead"). 69 bool is_alive; 70 }; 71 72 typedef std::vector<SourceInfo> SourceInfoList; 73 74 // Interface for consuming a NetLog entry. 75 class SourceTrackerInterface { 76 public: ~SourceTrackerInterface()77 virtual ~SourceTrackerInterface() {} 78 79 virtual void OnAddEntry(const ChromeNetLog::Entry& entry) = 0; 80 81 // Clears all the passively logged data from this tracker. 82 virtual void Clear() = 0; 83 84 // Appends all the captured entries to |out|. The ordering is undefined. 85 virtual void AppendAllEntries(ChromeNetLog::EntryList* out) const = 0; 86 }; 87 88 // This source tracker is intended for TYPE_NONE. All entries go into a 89 // circular buffer, and there is no concept of live/dead requests. 90 class GlobalSourceTracker : public SourceTrackerInterface { 91 public: 92 GlobalSourceTracker(); 93 ~GlobalSourceTracker(); 94 95 // SourceTrackerInterface implementation: 96 virtual void OnAddEntry(const ChromeNetLog::Entry& entry); 97 virtual void Clear(); 98 virtual void AppendAllEntries(ChromeNetLog::EntryList* out) const; 99 100 private: 101 typedef std::deque<ChromeNetLog::Entry> CircularEntryList; 102 CircularEntryList entries_; 103 DISALLOW_COPY_AND_ASSIGN(GlobalSourceTracker); 104 }; 105 106 // This class stores and manages the passively logged information for 107 // URLRequests/SocketStreams/ConnectJobs. 108 class SourceTracker : public SourceTrackerInterface { 109 public: 110 // Creates a SourceTracker that will track at most |max_num_sources|. 111 // Up to |max_graveyard_size| unreferenced sources will be kept around 112 // before deleting them for good. |parent| may be NULL, and points to 113 // the owning PassiveLogCollector (it is used when adding references 114 // to other sources). 115 SourceTracker(size_t max_num_sources, 116 size_t max_graveyard_size, 117 PassiveLogCollector* parent); 118 119 virtual ~SourceTracker(); 120 121 // SourceTrackerInterface implementation: 122 virtual void OnAddEntry(const ChromeNetLog::Entry& entry); 123 virtual void Clear(); 124 virtual void AppendAllEntries(ChromeNetLog::EntryList* out) const; 125 126 #ifdef UNIT_TEST 127 // Helper used to inspect the current state by unit-tests. 128 // Retuns a copy of the source infos held by the tracker. GetAllDeadOrAliveSources(bool is_alive)129 SourceInfoList GetAllDeadOrAliveSources(bool is_alive) const { 130 SourceInfoList result; 131 for (SourceIDToInfoMap::const_iterator it = sources_.begin(); 132 it != sources_.end(); ++it) { 133 if (it->second.is_alive == is_alive) 134 result.push_back(it->second); 135 } 136 return result; 137 } 138 #endif 139 140 protected: 141 enum Action { 142 ACTION_NONE, 143 ACTION_DELETE, 144 ACTION_MOVE_TO_GRAVEYARD, 145 }; 146 147 // Makes |info| hold a reference to |source|. This way |source| will be 148 // kept alive at least as long as |info|. 149 void AddReferenceToSourceDependency(const net::NetLog::Source& source, 150 SourceInfo* info); 151 152 private: 153 typedef base::hash_map<uint32, SourceInfo> SourceIDToInfoMap; 154 typedef std::deque<uint32> DeletionQueue; 155 156 // Updates |out_info| with the information from |entry|. Returns an action 157 // to perform for this map entry on completion. 158 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 159 SourceInfo* out_info) = 0; 160 161 // Removes |source_id| from |sources_|. This also releases any references 162 // to dependencies held by this source. 163 void DeleteSourceInfo(uint32 source_id); 164 165 // Adds |source_id| to the FIFO queue (graveyard) for deletion. 166 void AddToDeletionQueue(uint32 source_id); 167 168 // Removes |source_id| from the |deletion_queue_| container. 169 void EraseFromDeletionQueue(uint32 source_id); 170 171 // Adds/Releases a reference from the source with ID |source_id|. 172 // Use |offset=-1| to do a release, and |offset=1| for an addref. 173 void AdjustReferenceCountForSource(int offset, uint32 source_id); 174 175 // Releases all the references to sources held by |info|. 176 void ReleaseAllReferencesToDependencies(SourceInfo* info); 177 178 // This map contains all of the sources being tracked by this tracker. 179 // (It includes both the "live" sources, and the "dead" ones.) 180 SourceIDToInfoMap sources_; 181 182 size_t max_num_sources_; 183 size_t max_graveyard_size_; 184 185 // FIFO queue for entries in |sources_| that are no longer alive, and 186 // can be deleted. This buffer is also called "graveyard" elsewhere. We 187 // queue sources for deletion so they can persist a bit longer. 188 DeletionQueue deletion_queue_; 189 190 PassiveLogCollector* parent_; 191 192 DISALLOW_COPY_AND_ASSIGN(SourceTracker); 193 }; 194 195 // Specialization of SourceTracker for handling ConnectJobs. 196 class ConnectJobTracker : public SourceTracker { 197 public: 198 static const size_t kMaxNumSources; 199 static const size_t kMaxGraveyardSize; 200 201 explicit ConnectJobTracker(PassiveLogCollector* parent); 202 203 private: 204 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 205 SourceInfo* out_info); 206 DISALLOW_COPY_AND_ASSIGN(ConnectJobTracker); 207 }; 208 209 // Specialization of SourceTracker for handling Sockets. 210 class SocketTracker : public SourceTracker { 211 public: 212 static const size_t kMaxNumSources; 213 static const size_t kMaxGraveyardSize; 214 215 SocketTracker(); 216 217 private: 218 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 219 SourceInfo* out_info); 220 221 DISALLOW_COPY_AND_ASSIGN(SocketTracker); 222 }; 223 224 // Specialization of SourceTracker for handling net::URLRequest/SocketStream. 225 class RequestTracker : public SourceTracker { 226 public: 227 static const size_t kMaxNumSources; 228 static const size_t kMaxGraveyardSize; 229 230 explicit RequestTracker(PassiveLogCollector* parent); 231 232 private: 233 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 234 SourceInfo* out_info); 235 236 DISALLOW_COPY_AND_ASSIGN(RequestTracker); 237 }; 238 239 // Specialization of SourceTracker for handling 240 // SOURCE_INIT_PROXY_RESOLVER. 241 class InitProxyResolverTracker : public SourceTracker { 242 public: 243 static const size_t kMaxNumSources; 244 static const size_t kMaxGraveyardSize; 245 246 InitProxyResolverTracker(); 247 248 private: 249 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 250 SourceInfo* out_info); 251 252 DISALLOW_COPY_AND_ASSIGN(InitProxyResolverTracker); 253 }; 254 255 // Tracks the log entries for the last seen SOURCE_SPDY_SESSION. 256 class SpdySessionTracker : public SourceTracker { 257 public: 258 static const size_t kMaxNumSources; 259 static const size_t kMaxGraveyardSize; 260 261 SpdySessionTracker(); 262 263 private: 264 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 265 SourceInfo* out_info); 266 267 DISALLOW_COPY_AND_ASSIGN(SpdySessionTracker); 268 }; 269 270 // Tracks the log entries for the last seen SOURCE_HOST_RESOLVER_IMPL_REQUEST. 271 class DNSRequestTracker : public SourceTracker { 272 public: 273 static const size_t kMaxNumSources; 274 static const size_t kMaxGraveyardSize; 275 276 DNSRequestTracker(); 277 278 private: 279 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 280 SourceInfo* out_info); 281 282 DISALLOW_COPY_AND_ASSIGN(DNSRequestTracker); 283 }; 284 285 // Tracks the log entries for the last seen SOURCE_HOST_RESOLVER_IMPL_JOB. 286 class DNSJobTracker : public SourceTracker { 287 public: 288 static const size_t kMaxNumSources; 289 static const size_t kMaxGraveyardSize; 290 291 DNSJobTracker(); 292 293 private: 294 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 295 SourceInfo* out_info); 296 297 DISALLOW_COPY_AND_ASSIGN(DNSJobTracker); 298 }; 299 300 // Tracks the log entries for the last seen SOURCE_DISK_CACHE_ENTRY. 301 class DiskCacheEntryTracker : public SourceTracker { 302 public: 303 static const size_t kMaxNumSources; 304 static const size_t kMaxGraveyardSize; 305 306 DiskCacheEntryTracker(); 307 308 private: 309 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 310 SourceInfo* out_info); 311 312 DISALLOW_COPY_AND_ASSIGN(DiskCacheEntryTracker); 313 }; 314 315 // Tracks the log entries for the last seen SOURCE_DISK_CACHE_ENTRY. 316 class MemCacheEntryTracker : public SourceTracker { 317 public: 318 static const size_t kMaxNumSources; 319 static const size_t kMaxGraveyardSize; 320 321 MemCacheEntryTracker(); 322 323 protected: 324 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 325 SourceInfo* out_info); 326 327 private: 328 DISALLOW_COPY_AND_ASSIGN(MemCacheEntryTracker); 329 }; 330 331 class HttpStreamJobTracker : public SourceTracker { 332 public: 333 static const size_t kMaxNumSources; 334 static const size_t kMaxGraveyardSize; 335 336 explicit HttpStreamJobTracker(PassiveLogCollector* parent); 337 338 private: 339 virtual Action DoAddEntry(const ChromeNetLog::Entry& entry, 340 SourceInfo* out_info); 341 DISALLOW_COPY_AND_ASSIGN(HttpStreamJobTracker); 342 }; 343 344 345 PassiveLogCollector(); 346 ~PassiveLogCollector(); 347 348 // ThreadSafeObserver implementation: 349 virtual void OnAddEntry(net::NetLog::EventType type, 350 const base::TimeTicks& time, 351 const net::NetLog::Source& source, 352 net::NetLog::EventPhase phase, 353 net::NetLog::EventParameters* params); 354 355 // Clears all of the passively logged data. 356 void Clear(); 357 358 // Fills |out| with the full list of events that have been passively 359 // captured. The list is ordered by capture time. 360 void GetAllCapturedEvents(ChromeNetLog::EntryList* out) const; 361 362 private: 363 // Returns the tracker to use for sources of type |source_type|, or NULL. 364 SourceTrackerInterface* GetTrackerForSourceType( 365 net::NetLog::SourceType source_type); 366 367 FRIEND_TEST_ALL_PREFIXES(PassiveLogCollectorTest, 368 HoldReferenceToDependentSource); 369 FRIEND_TEST_ALL_PREFIXES(PassiveLogCollectorTest, 370 HoldReferenceToDeletedSource); 371 372 GlobalSourceTracker global_source_tracker_; 373 ConnectJobTracker connect_job_tracker_; 374 SocketTracker socket_tracker_; 375 RequestTracker url_request_tracker_; 376 RequestTracker socket_stream_tracker_; 377 InitProxyResolverTracker init_proxy_resolver_tracker_; 378 SpdySessionTracker spdy_session_tracker_; 379 DNSRequestTracker dns_request_tracker_; 380 DNSJobTracker dns_job_tracker_; 381 DiskCacheEntryTracker disk_cache_entry_tracker_; 382 MemCacheEntryTracker mem_cache_entry_tracker_; 383 HttpStreamJobTracker http_stream_job_tracker_; 384 385 // This array maps each NetLog::SourceType to one of the tracker instances 386 // defined above. Use of this array avoid duplicating the list of trackers 387 // elsewhere. 388 SourceTrackerInterface* trackers_[net::NetLog::SOURCE_COUNT]; 389 390 // The count of how many events have flowed through this log. Used to set the 391 // "order" field on captured events. 392 uint32 num_events_seen_; 393 394 DISALLOW_COPY_AND_ASSIGN(PassiveLogCollector); 395 }; 396 397 #endif // CHROME_BROWSER_NET_PASSIVE_LOG_COLLECTOR_H_ 398