Home | History | Annotate | Download | only in net
      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 #include "chrome/browser/net/passive_log_collector.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "base/compiler_specific.h"
     10 #include "base/string_util.h"
     11 #include "base/format_macros.h"
     12 #include "net/url_request/url_request_netlog_params.h"
     13 
     14 namespace {
     15 
     16 // TODO(eroman): Do something with the truncation count.
     17 
     18 const size_t kMaxNumEntriesPerLog = 30;
     19 
     20 void AddEntryToSourceInfo(const ChromeNetLog::Entry& entry,
     21                           PassiveLogCollector::SourceInfo* out_info) {
     22   // Start dropping new entries when the log has gotten too big.
     23   if (out_info->entries.size() + 1 <= kMaxNumEntriesPerLog) {
     24     out_info->entries.push_back(entry);
     25   } else {
     26     out_info->num_entries_truncated += 1;
     27     out_info->entries[kMaxNumEntriesPerLog - 1] = entry;
     28   }
     29 }
     30 
     31 // Comparator to sort entries by their |order| property, ascending.
     32 bool SortByOrderComparator(const ChromeNetLog::Entry& a,
     33                            const ChromeNetLog::Entry& b) {
     34   return a.order < b.order;
     35 }
     36 
     37 }  // namespace
     38 
     39 PassiveLogCollector::SourceInfo::SourceInfo()
     40     : source_id(net::NetLog::Source::kInvalidId),
     41       num_entries_truncated(0),
     42       reference_count(0),
     43       is_alive(true) {
     44 }
     45 
     46 PassiveLogCollector::SourceInfo::~SourceInfo() {}
     47 
     48 //----------------------------------------------------------------------------
     49 // PassiveLogCollector
     50 //----------------------------------------------------------------------------
     51 
     52 PassiveLogCollector::PassiveLogCollector()
     53     : ThreadSafeObserver(net::NetLog::LOG_BASIC),
     54       ALLOW_THIS_IN_INITIALIZER_LIST(connect_job_tracker_(this)),
     55       ALLOW_THIS_IN_INITIALIZER_LIST(url_request_tracker_(this)),
     56       ALLOW_THIS_IN_INITIALIZER_LIST(socket_stream_tracker_(this)),
     57       ALLOW_THIS_IN_INITIALIZER_LIST(http_stream_job_tracker_(this)),
     58       num_events_seen_(0) {
     59 
     60   // Define the mapping between source types and the tracker objects.
     61   memset(&trackers_[0], 0, sizeof(trackers_));
     62   trackers_[net::NetLog::SOURCE_NONE] = &global_source_tracker_;
     63   trackers_[net::NetLog::SOURCE_URL_REQUEST] = &url_request_tracker_;
     64   trackers_[net::NetLog::SOURCE_SOCKET_STREAM] = &socket_stream_tracker_;
     65   trackers_[net::NetLog::SOURCE_CONNECT_JOB] = &connect_job_tracker_;
     66   trackers_[net::NetLog::SOURCE_SOCKET] = &socket_tracker_;
     67   trackers_[net::NetLog::SOURCE_INIT_PROXY_RESOLVER] =
     68       &init_proxy_resolver_tracker_;
     69   trackers_[net::NetLog::SOURCE_SPDY_SESSION] = &spdy_session_tracker_;
     70   trackers_[net::NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST] =
     71       &dns_request_tracker_;
     72   trackers_[net::NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB] = &dns_job_tracker_;
     73   trackers_[net::NetLog::SOURCE_DISK_CACHE_ENTRY] = &disk_cache_entry_tracker_;
     74   trackers_[net::NetLog::SOURCE_MEMORY_CACHE_ENTRY] = &mem_cache_entry_tracker_;
     75   trackers_[net::NetLog::SOURCE_HTTP_STREAM_JOB] = &http_stream_job_tracker_;
     76   // Make sure our mapping is up-to-date.
     77   for (size_t i = 0; i < arraysize(trackers_); ++i)
     78     DCHECK(trackers_[i]) << "Unhandled SourceType: " << i;
     79 }
     80 
     81 PassiveLogCollector::~PassiveLogCollector() {
     82 }
     83 
     84 void PassiveLogCollector::OnAddEntry(
     85     net::NetLog::EventType type,
     86     const base::TimeTicks& time,
     87     const net::NetLog::Source& source,
     88     net::NetLog::EventPhase phase,
     89     net::NetLog::EventParameters* params) {
     90   AssertNetLogLockAcquired();
     91   // Package the parameters into a single struct for convenience.
     92   ChromeNetLog::Entry entry(num_events_seen_++, type, time, source, phase,
     93                             params);
     94 
     95   SourceTrackerInterface* tracker = GetTrackerForSourceType(entry.source.type);
     96   if (tracker)
     97     tracker->OnAddEntry(entry);
     98 }
     99 
    100 void PassiveLogCollector::Clear() {
    101   AssertNetLogLockAcquired();
    102   for (size_t i = 0; i < arraysize(trackers_); ++i)
    103     trackers_[i]->Clear();
    104 }
    105 
    106 PassiveLogCollector::SourceTrackerInterface*
    107 PassiveLogCollector::GetTrackerForSourceType(
    108     net::NetLog::SourceType source_type) {
    109   CHECK_LT(source_type, static_cast<int>(arraysize(trackers_)));
    110   CHECK_GE(source_type, 0);
    111   return trackers_[source_type];
    112 }
    113 
    114 void PassiveLogCollector::GetAllCapturedEvents(
    115     ChromeNetLog::EntryList* out) const {
    116   AssertNetLogLockAcquired();
    117   out->clear();
    118 
    119   // Append all of the captured entries held by the various trackers to
    120   // |out|.
    121   for (size_t i = 0; i < arraysize(trackers_); ++i)
    122     trackers_[i]->AppendAllEntries(out);
    123 
    124   // Now sort the list of entries by their insertion time (ascending).
    125   std::sort(out->begin(), out->end(), &SortByOrderComparator);
    126 }
    127 
    128 std::string PassiveLogCollector::SourceInfo::GetURL() const {
    129   // Note: we look at the first *two* entries, since the outer REQUEST_ALIVE
    130   // doesn't actually contain any data.
    131   for (size_t i = 0; i < 2 && i < entries.size(); ++i) {
    132     const ChromeNetLog::Entry& entry = entries[i];
    133     if (entry.phase == net::NetLog::PHASE_BEGIN && entry.params) {
    134       switch (entry.type) {
    135         case net::NetLog::TYPE_URL_REQUEST_START_JOB:
    136           return static_cast<net::URLRequestStartEventParameters*>(
    137               entry.params.get())->url().possibly_invalid_spec();
    138         case net::NetLog::TYPE_SOCKET_STREAM_CONNECT:
    139           return static_cast<net::NetLogStringParameter*>(
    140               entry.params.get())->value();
    141         default:
    142           break;
    143       }
    144     }
    145   }
    146   return std::string();
    147 }
    148 
    149 //----------------------------------------------------------------------------
    150 // GlobalSourceTracker
    151 //----------------------------------------------------------------------------
    152 
    153 PassiveLogCollector::GlobalSourceTracker::GlobalSourceTracker() {}
    154 PassiveLogCollector::GlobalSourceTracker::~GlobalSourceTracker() {}
    155 
    156 void PassiveLogCollector::GlobalSourceTracker::OnAddEntry(
    157     const ChromeNetLog::Entry& entry) {
    158   const size_t kMaxEntries = 30u;
    159   entries_.push_back(entry);
    160   if (entries_.size() > kMaxEntries)
    161     entries_.pop_front();
    162 }
    163 
    164 void PassiveLogCollector::GlobalSourceTracker::Clear() {
    165   entries_.clear();
    166 }
    167 
    168 void PassiveLogCollector::GlobalSourceTracker::AppendAllEntries(
    169     ChromeNetLog::EntryList* out) const {
    170   out->insert(out->end(), entries_.begin(), entries_.end());
    171 }
    172 
    173 //----------------------------------------------------------------------------
    174 // SourceTracker
    175 //----------------------------------------------------------------------------
    176 
    177 PassiveLogCollector::SourceTracker::SourceTracker(
    178     size_t max_num_sources,
    179     size_t max_graveyard_size,
    180     PassiveLogCollector* parent)
    181     : max_num_sources_(max_num_sources),
    182       max_graveyard_size_(max_graveyard_size),
    183       parent_(parent) {
    184 }
    185 
    186 PassiveLogCollector::SourceTracker::~SourceTracker() {}
    187 
    188 void PassiveLogCollector::SourceTracker::OnAddEntry(
    189     const ChromeNetLog::Entry& entry) {
    190   // Lookup or insert a new entry into the bounded map.
    191   SourceIDToInfoMap::iterator it = sources_.find(entry.source.id);
    192   if (it == sources_.end()) {
    193     if (sources_.size() >= max_num_sources_) {
    194       LOG(WARNING) << "The passive log data has grown larger "
    195                       "than expected, resetting";
    196       Clear();
    197     }
    198     it = sources_.insert(
    199         SourceIDToInfoMap::value_type(entry.source.id, SourceInfo())).first;
    200     it->second.source_id = entry.source.id;
    201   }
    202 
    203   SourceInfo& info = it->second;
    204   Action result = DoAddEntry(entry, &info);
    205 
    206   if (result != ACTION_NONE) {
    207     // We are either queuing it for deletion, or deleting it immediately.
    208     // If someone else holds a reference to this source, defer the deletion
    209     // until all the references are released.
    210     info.is_alive = false;
    211     if (info.reference_count == 0) {
    212       switch (result) {
    213         case ACTION_MOVE_TO_GRAVEYARD:
    214           AddToDeletionQueue(info.source_id);
    215           break;
    216         case ACTION_DELETE:
    217           DeleteSourceInfo(info.source_id);
    218           break;
    219         default:
    220           NOTREACHED();
    221           break;
    222       }
    223     }
    224   }
    225 }
    226 
    227 void PassiveLogCollector::SourceTracker::DeleteSourceInfo(
    228     uint32 source_id) {
    229   SourceIDToInfoMap::iterator it = sources_.find(source_id);
    230   if (it == sources_.end()) {
    231     // TODO(eroman): Is this happening? And if so, why. Remove this
    232     //               once the cause is understood.
    233     LOG(WARNING) << "Tried to delete info for nonexistent source";
    234     return;
    235   }
    236   // The source should not be in the deletion queue.
    237   CHECK(std::find(deletion_queue_.begin(), deletion_queue_.end(),
    238                   source_id) == deletion_queue_.end());
    239   ReleaseAllReferencesToDependencies(&(it->second));
    240   sources_.erase(it);
    241 }
    242 
    243 void PassiveLogCollector::SourceTracker::Clear() {
    244   deletion_queue_.clear();
    245 
    246   // Release all references held to dependent sources.
    247   for (SourceIDToInfoMap::iterator it = sources_.begin();
    248        it != sources_.end();
    249        ++it) {
    250     ReleaseAllReferencesToDependencies(&(it->second));
    251   }
    252   sources_.clear();
    253 }
    254 
    255 void PassiveLogCollector::SourceTracker::AppendAllEntries(
    256     ChromeNetLog::EntryList* out) const {
    257   // Append all of the entries for each of the sources.
    258   for (SourceIDToInfoMap::const_iterator it = sources_.begin();
    259        it != sources_.end();
    260        ++it) {
    261     const SourceInfo& info = it->second;
    262     out->insert(out->end(), info.entries.begin(), info.entries.end());
    263   }
    264 }
    265 
    266 void PassiveLogCollector::SourceTracker::AddToDeletionQueue(
    267     uint32 source_id) {
    268   DCHECK(sources_.find(source_id) != sources_.end());
    269   DCHECK(!sources_.find(source_id)->second.is_alive);
    270   DCHECK_GE(sources_.find(source_id)->second.reference_count, 0);
    271   DCHECK_LE(deletion_queue_.size(), max_graveyard_size_);
    272 
    273   DCHECK(std::find(deletion_queue_.begin(), deletion_queue_.end(),
    274                    source_id) == deletion_queue_.end());
    275   deletion_queue_.push_back(source_id);
    276 
    277   // After the deletion queue has reached its maximum size, start
    278   // deleting sources in FIFO order.
    279   if (deletion_queue_.size() > max_graveyard_size_) {
    280     uint32 oldest = deletion_queue_.front();
    281     deletion_queue_.pop_front();
    282     DeleteSourceInfo(oldest);
    283   }
    284 }
    285 
    286 void PassiveLogCollector::SourceTracker::EraseFromDeletionQueue(
    287     uint32 source_id) {
    288   DeletionQueue::iterator it =
    289       std::remove(deletion_queue_.begin(), deletion_queue_.end(),
    290                   source_id);
    291   CHECK(it != deletion_queue_.end());
    292   deletion_queue_.erase(it);
    293 }
    294 
    295 void PassiveLogCollector::SourceTracker::AdjustReferenceCountForSource(
    296     int offset, uint32 source_id) {
    297   DCHECK(offset == -1 || offset == 1) << "invalid offset: " << offset;
    298 
    299   // In general it is invalid to call AdjustReferenceCountForSource() on
    300   // source that doesn't exist. However, it is possible that if
    301   // SourceTracker::Clear() was previously called this can happen.
    302   SourceIDToInfoMap::iterator it = sources_.find(source_id);
    303   if (it == sources_.end()) {
    304     LOG(WARNING) << "Released a reference to nonexistent source.";
    305     return;
    306   }
    307 
    308   SourceInfo& info = it->second;
    309   DCHECK_GE(info.reference_count, 0);
    310   info.reference_count += offset;
    311 
    312   bool released_unmatched_reference = info.reference_count < 0;
    313   if (released_unmatched_reference) {
    314     // In general this shouldn't happen, however it is possible to reach this
    315     // state if SourceTracker::Clear() was called earlier.
    316     LOG(WARNING) << "Released unmatched reference count.";
    317     info.reference_count = 0;
    318   }
    319 
    320   if (!info.is_alive) {
    321     if (info.reference_count == 1 && offset == 1) {
    322       // If we just added a reference to a dead source that had no references,
    323       // it must have been in the deletion queue, so remove it from the queue.
    324       EraseFromDeletionQueue(source_id);
    325     } else if (info.reference_count == 0) {
    326       if (released_unmatched_reference)
    327         EraseFromDeletionQueue(source_id);
    328       // If we just released the final reference to a dead source, go ahead
    329       // and delete it right away.
    330       DeleteSourceInfo(source_id);
    331     }
    332   }
    333 }
    334 
    335 void PassiveLogCollector::SourceTracker::AddReferenceToSourceDependency(
    336     const net::NetLog::Source& source, SourceInfo* info) {
    337   // Find the tracker which should be holding |source|.
    338   DCHECK(parent_);
    339   DCHECK_NE(source.type, net::NetLog::SOURCE_NONE);
    340   SourceTracker* tracker = static_cast<SourceTracker*>(
    341       parent_->GetTrackerForSourceType(source.type));
    342   DCHECK(tracker);
    343 
    344   // Tell the owning tracker to increment the reference count of |source|.
    345   tracker->AdjustReferenceCountForSource(1, source.id);
    346 
    347   // Make a note to release this reference once |info| is destroyed.
    348   info->dependencies.push_back(source);
    349 }
    350 
    351 void PassiveLogCollector::SourceTracker::ReleaseAllReferencesToDependencies(
    352     SourceInfo* info) {
    353   // Release all references |info| was holding to other sources.
    354   for (SourceDependencyList::const_iterator it = info->dependencies.begin();
    355        it != info->dependencies.end(); ++it) {
    356     const net::NetLog::Source& source = *it;
    357 
    358     // Find the tracker which should be holding |source|.
    359     DCHECK(parent_);
    360     DCHECK_NE(source.type, net::NetLog::SOURCE_NONE);
    361     SourceTracker* tracker = static_cast<SourceTracker*>(
    362         parent_->GetTrackerForSourceType(source.type));
    363     DCHECK(tracker);
    364 
    365     // Tell the owning tracker to decrement the reference count of |source|.
    366     tracker->AdjustReferenceCountForSource(-1, source.id);
    367   }
    368 
    369   info->dependencies.clear();
    370 }
    371 
    372 //----------------------------------------------------------------------------
    373 // ConnectJobTracker
    374 //----------------------------------------------------------------------------
    375 
    376 const size_t PassiveLogCollector::ConnectJobTracker::kMaxNumSources = 100;
    377 const size_t PassiveLogCollector::ConnectJobTracker::kMaxGraveyardSize = 15;
    378 
    379 PassiveLogCollector::ConnectJobTracker::ConnectJobTracker(
    380     PassiveLogCollector* parent)
    381     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, parent) {
    382 }
    383 
    384 PassiveLogCollector::SourceTracker::Action
    385 PassiveLogCollector::ConnectJobTracker::DoAddEntry(
    386     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    387   AddEntryToSourceInfo(entry, out_info);
    388 
    389   if (entry.type == net::NetLog::TYPE_CONNECT_JOB_SET_SOCKET) {
    390     const net::NetLog::Source& source_dependency =
    391         static_cast<net::NetLogSourceParameter*>(entry.params.get())->value();
    392     AddReferenceToSourceDependency(source_dependency, out_info);
    393   }
    394 
    395   // If this is the end of the connect job, move the source to the graveyard.
    396   if (entry.type == net::NetLog::TYPE_SOCKET_POOL_CONNECT_JOB &&
    397       entry.phase == net::NetLog::PHASE_END) {
    398     return ACTION_MOVE_TO_GRAVEYARD;
    399   }
    400 
    401   return ACTION_NONE;
    402 }
    403 
    404 //----------------------------------------------------------------------------
    405 // SocketTracker
    406 //----------------------------------------------------------------------------
    407 
    408 const size_t PassiveLogCollector::SocketTracker::kMaxNumSources = 200;
    409 const size_t PassiveLogCollector::SocketTracker::kMaxGraveyardSize = 15;
    410 
    411 PassiveLogCollector::SocketTracker::SocketTracker()
    412     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
    413 }
    414 
    415 PassiveLogCollector::SourceTracker::Action
    416 PassiveLogCollector::SocketTracker::DoAddEntry(const ChromeNetLog::Entry& entry,
    417                                                SourceInfo* out_info) {
    418   // TODO(eroman): aggregate the byte counts once truncation starts to happen,
    419   //               to summarize transaction read/writes for each SOCKET_IN_USE
    420   //               section.
    421   if (entry.type == net::NetLog::TYPE_SOCKET_BYTES_SENT ||
    422       entry.type == net::NetLog::TYPE_SOCKET_BYTES_RECEIVED) {
    423     return ACTION_NONE;
    424   }
    425 
    426   AddEntryToSourceInfo(entry, out_info);
    427 
    428   if (entry.type == net::NetLog::TYPE_SOCKET_ALIVE &&
    429       entry.phase == net::NetLog::PHASE_END) {
    430     return ACTION_MOVE_TO_GRAVEYARD;
    431   }
    432 
    433   return ACTION_NONE;
    434 }
    435 
    436 //----------------------------------------------------------------------------
    437 // RequestTracker
    438 //----------------------------------------------------------------------------
    439 
    440 const size_t PassiveLogCollector::RequestTracker::kMaxNumSources = 100;
    441 const size_t PassiveLogCollector::RequestTracker::kMaxGraveyardSize = 25;
    442 
    443 PassiveLogCollector::RequestTracker::RequestTracker(PassiveLogCollector* parent)
    444     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, parent) {
    445 }
    446 
    447 PassiveLogCollector::SourceTracker::Action
    448 PassiveLogCollector::RequestTracker::DoAddEntry(
    449     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    450   if (entry.type == net::NetLog::TYPE_HTTP_STREAM_REQUEST_BOUND_TO_JOB) {
    451     const net::NetLog::Source& source_dependency =
    452         static_cast<net::NetLogSourceParameter*>(entry.params.get())->value();
    453     AddReferenceToSourceDependency(source_dependency, out_info);
    454   }
    455 
    456   AddEntryToSourceInfo(entry, out_info);
    457 
    458   // If the request has ended, move it to the graveyard.
    459   if (entry.type == net::NetLog::TYPE_REQUEST_ALIVE &&
    460       entry.phase == net::NetLog::PHASE_END) {
    461     if (StartsWithASCII(out_info->GetURL(), "chrome://", false)) {
    462       // Avoid sending "chrome://" requests to the graveyard, since it just
    463       // adds to clutter.
    464       return ACTION_DELETE;
    465     }
    466     return ACTION_MOVE_TO_GRAVEYARD;
    467   }
    468 
    469   return ACTION_NONE;
    470 }
    471 
    472 //----------------------------------------------------------------------------
    473 // InitProxyResolverTracker
    474 //----------------------------------------------------------------------------
    475 
    476 const size_t PassiveLogCollector::InitProxyResolverTracker::kMaxNumSources = 20;
    477 const size_t PassiveLogCollector::InitProxyResolverTracker::kMaxGraveyardSize =
    478     3;
    479 
    480 PassiveLogCollector::InitProxyResolverTracker::InitProxyResolverTracker()
    481     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
    482 }
    483 
    484 PassiveLogCollector::SourceTracker::Action
    485 PassiveLogCollector::InitProxyResolverTracker::DoAddEntry(
    486     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    487   AddEntryToSourceInfo(entry, out_info);
    488   if (entry.type == net::NetLog::TYPE_INIT_PROXY_RESOLVER &&
    489       entry.phase == net::NetLog::PHASE_END) {
    490     return ACTION_MOVE_TO_GRAVEYARD;
    491   } else {
    492     return ACTION_NONE;
    493   }
    494 }
    495 
    496 //----------------------------------------------------------------------------
    497 // SpdySessionTracker
    498 //----------------------------------------------------------------------------
    499 
    500 const size_t PassiveLogCollector::SpdySessionTracker::kMaxNumSources = 50;
    501 const size_t PassiveLogCollector::SpdySessionTracker::kMaxGraveyardSize = 10;
    502 
    503 PassiveLogCollector::SpdySessionTracker::SpdySessionTracker()
    504     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
    505 }
    506 
    507 PassiveLogCollector::SourceTracker::Action
    508 PassiveLogCollector::SpdySessionTracker::DoAddEntry(
    509     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    510   AddEntryToSourceInfo(entry, out_info);
    511   if (entry.type == net::NetLog::TYPE_SPDY_SESSION &&
    512       entry.phase == net::NetLog::PHASE_END) {
    513     return ACTION_MOVE_TO_GRAVEYARD;
    514   } else {
    515     return ACTION_NONE;
    516   }
    517 }
    518 
    519 //----------------------------------------------------------------------------
    520 // DNSRequestTracker
    521 //----------------------------------------------------------------------------
    522 
    523 const size_t PassiveLogCollector::DNSRequestTracker::kMaxNumSources = 200;
    524 const size_t PassiveLogCollector::DNSRequestTracker::kMaxGraveyardSize = 20;
    525 
    526 PassiveLogCollector::DNSRequestTracker::DNSRequestTracker()
    527     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
    528 }
    529 
    530 PassiveLogCollector::SourceTracker::Action
    531 PassiveLogCollector::DNSRequestTracker::DoAddEntry(
    532     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    533   AddEntryToSourceInfo(entry, out_info);
    534   if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST &&
    535       entry.phase == net::NetLog::PHASE_END) {
    536     return ACTION_MOVE_TO_GRAVEYARD;
    537   } else {
    538     return ACTION_NONE;
    539   }
    540 }
    541 
    542 //----------------------------------------------------------------------------
    543 // DNSJobTracker
    544 //----------------------------------------------------------------------------
    545 
    546 const size_t PassiveLogCollector::DNSJobTracker::kMaxNumSources = 100;
    547 const size_t PassiveLogCollector::DNSJobTracker::kMaxGraveyardSize = 15;
    548 
    549 PassiveLogCollector::DNSJobTracker::DNSJobTracker()
    550     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
    551 }
    552 
    553 PassiveLogCollector::SourceTracker::Action
    554 PassiveLogCollector::DNSJobTracker::DoAddEntry(const ChromeNetLog::Entry& entry,
    555                                                SourceInfo* out_info) {
    556   AddEntryToSourceInfo(entry, out_info);
    557   if (entry.type == net::NetLog::TYPE_HOST_RESOLVER_IMPL_JOB &&
    558       entry.phase == net::NetLog::PHASE_END) {
    559     return ACTION_MOVE_TO_GRAVEYARD;
    560   } else {
    561     return ACTION_NONE;
    562   }
    563 }
    564 
    565 //----------------------------------------------------------------------------
    566 // DiskCacheEntryTracker
    567 //----------------------------------------------------------------------------
    568 
    569 const size_t PassiveLogCollector::DiskCacheEntryTracker::kMaxNumSources = 100;
    570 const size_t PassiveLogCollector::DiskCacheEntryTracker::kMaxGraveyardSize = 25;
    571 
    572 PassiveLogCollector::DiskCacheEntryTracker::DiskCacheEntryTracker()
    573     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
    574 }
    575 
    576 PassiveLogCollector::SourceTracker::Action
    577 PassiveLogCollector::DiskCacheEntryTracker::DoAddEntry(
    578     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    579   AddEntryToSourceInfo(entry, out_info);
    580 
    581   // If the request has ended, move it to the graveyard.
    582   if (entry.type == net::NetLog::TYPE_DISK_CACHE_ENTRY_IMPL &&
    583       entry.phase == net::NetLog::PHASE_END) {
    584     return ACTION_MOVE_TO_GRAVEYARD;
    585   }
    586 
    587   return ACTION_NONE;
    588 }
    589 
    590 //----------------------------------------------------------------------------
    591 // MemCacheEntryTracker
    592 //----------------------------------------------------------------------------
    593 
    594 const size_t PassiveLogCollector::MemCacheEntryTracker::kMaxNumSources = 100;
    595 const size_t PassiveLogCollector::MemCacheEntryTracker::kMaxGraveyardSize = 25;
    596 
    597 PassiveLogCollector::MemCacheEntryTracker::MemCacheEntryTracker()
    598     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, NULL) {
    599 }
    600 
    601 PassiveLogCollector::SourceTracker::Action
    602 PassiveLogCollector::MemCacheEntryTracker::DoAddEntry(
    603     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    604   AddEntryToSourceInfo(entry, out_info);
    605 
    606   // If the request has ended, move it to the graveyard.
    607   if (entry.type == net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL &&
    608       entry.phase == net::NetLog::PHASE_END) {
    609     return ACTION_MOVE_TO_GRAVEYARD;
    610   }
    611 
    612   return ACTION_NONE;
    613 }
    614 
    615 //----------------------------------------------------------------------------
    616 // HttpStreamJobTracker
    617 //----------------------------------------------------------------------------
    618 
    619 const size_t PassiveLogCollector::HttpStreamJobTracker::kMaxNumSources = 100;
    620 const size_t PassiveLogCollector::HttpStreamJobTracker::kMaxGraveyardSize = 25;
    621 
    622 PassiveLogCollector::HttpStreamJobTracker::HttpStreamJobTracker(
    623     PassiveLogCollector* parent)
    624     : SourceTracker(kMaxNumSources, kMaxGraveyardSize, parent) {
    625 }
    626 
    627 PassiveLogCollector::SourceTracker::Action
    628 PassiveLogCollector::HttpStreamJobTracker::DoAddEntry(
    629     const ChromeNetLog::Entry& entry, SourceInfo* out_info) {
    630   if (entry.type == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_CONNECT_JOB ||
    631       entry.type == net::NetLog::TYPE_SOCKET_POOL_BOUND_TO_SOCKET) {
    632     const net::NetLog::Source& source_dependency =
    633         static_cast<net::NetLogSourceParameter*>(entry.params.get())->value();
    634     AddReferenceToSourceDependency(source_dependency, out_info);
    635   }
    636 
    637   AddEntryToSourceInfo(entry, out_info);
    638 
    639   // If the request has ended, move it to the graveyard.
    640   if (entry.type == net::NetLog::TYPE_HTTP_STREAM_JOB &&
    641       entry.phase == net::NetLog::PHASE_END) {
    642     return ACTION_MOVE_TO_GRAVEYARD;
    643   }
    644 
    645   return ACTION_NONE;
    646 }
    647