• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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