passive_log_collector.h revision dc0f95d653279beabeb9817299e2902918ba123e
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.
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.
39class 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:
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.
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  class HttpStreamJobTracker : public SourceTracker {
316   public:
317    static const size_t kMaxNumSources;
318    static const size_t kMaxGraveyardSize;
319
320    explicit HttpStreamJobTracker(PassiveLogCollector* parent);
321
322   private:
323    virtual Action DoAddEntry(const ChromeNetLog::Entry& entry,
324                              SourceInfo* out_info);
325    DISALLOW_COPY_AND_ASSIGN(HttpStreamJobTracker);
326  };
327
328
329  PassiveLogCollector();
330  ~PassiveLogCollector();
331
332  // ThreadSafeObserver implementation:
333  virtual void OnAddEntry(net::NetLog::EventType type,
334                          const base::TimeTicks& time,
335                          const net::NetLog::Source& source,
336                          net::NetLog::EventPhase phase,
337                          net::NetLog::EventParameters* params);
338
339  // Clears all of the passively logged data.
340  void Clear();
341
342  // Fills |out| with the full list of events that have been passively
343  // captured. The list is ordered by capture time.
344  void GetAllCapturedEvents(ChromeNetLog::EntryList* out) const;
345
346 private:
347  // Returns the tracker to use for sources of type |source_type|, or NULL.
348  SourceTrackerInterface* GetTrackerForSourceType_(
349      net::NetLog::SourceType source_type);
350
351  FRIEND_TEST_ALL_PREFIXES(PassiveLogCollectorTest,
352                           HoldReferenceToDependentSource);
353  FRIEND_TEST_ALL_PREFIXES(PassiveLogCollectorTest,
354                           HoldReferenceToDeletedSource);
355
356  GlobalSourceTracker global_source_tracker_;
357  ConnectJobTracker connect_job_tracker_;
358  SocketTracker socket_tracker_;
359  RequestTracker url_request_tracker_;
360  RequestTracker socket_stream_tracker_;
361  InitProxyResolverTracker init_proxy_resolver_tracker_;
362  SpdySessionTracker spdy_session_tracker_;
363  DNSRequestTracker dns_request_tracker_;
364  DNSJobTracker dns_job_tracker_;
365  DiskCacheEntryTracker disk_cache_entry_tracker_;
366  HttpStreamJobTracker http_stream_job_tracker_;
367
368  // This array maps each NetLog::SourceType to one of the tracker instances
369  // defined above. Use of this array avoid duplicating the list of trackers
370  // elsewhere.
371  SourceTrackerInterface* trackers_[net::NetLog::SOURCE_COUNT];
372
373  // The count of how many events have flowed through this log. Used to set the
374  // "order" field on captured events.
375  uint32 num_events_seen_;
376
377  DISALLOW_COPY_AND_ASSIGN(PassiveLogCollector);
378};
379
380#endif  // CHROME_BROWSER_NET_PASSIVE_LOG_COLLECTOR_H_
381