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