1// Copyright (c) 2012 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 5var EventsTracker = (function() { 6 'use strict'; 7 8 /** 9 * This class keeps track of all NetLog events. 10 * It receives events from the browser and when loading a log file, and passes 11 * them on to all its observers. 12 * 13 * @constructor 14 */ 15 function EventsTracker() { 16 assertFirstConstructorCall(EventsTracker); 17 18 this.capturedEvents_ = []; 19 this.observers_ = []; 20 21 // Controls how large |capturedEvents_| can grow. 22 this.softLimit_ = Infinity; 23 this.hardLimit_ = Infinity; 24 } 25 26 cr.addSingletonGetter(EventsTracker); 27 28 EventsTracker.prototype = { 29 /** 30 * Returns a list of all captured events. 31 */ 32 getAllCapturedEvents: function() { 33 return this.capturedEvents_; 34 }, 35 36 /** 37 * Returns the number of events that were captured. 38 */ 39 getNumCapturedEvents: function() { 40 return this.capturedEvents_.length; 41 }, 42 43 /** 44 * Deletes all the tracked events, and notifies any observers. 45 */ 46 deleteAllLogEntries: function() { 47 timeutil.clearBaseTime(); 48 this.capturedEvents_ = []; 49 for (var i = 0; i < this.observers_.length; ++i) 50 this.observers_[i].onAllLogEntriesDeleted(); 51 }, 52 53 /** 54 * Adds captured events, and broadcasts them to any observers. 55 */ 56 addLogEntries: function(logEntries) { 57 // When reloading a page, it's possible to receive events before 58 // Constants. Discard those events, as they can cause the fake 59 // "REQUEST_ALIVE" events for pre-existing requests not be the first 60 // events for those requests. 61 if (Constants == null) 62 return; 63 // This can happen when loading logs with no events. 64 if (!logEntries.length) 65 return; 66 67 if (!timeutil.isBaseTimeSet()) { 68 timeutil.setBaseTime( 69 timeutil.convertTimeTicksToTime(logEntries[0].time)); 70 } 71 72 this.capturedEvents_ = this.capturedEvents_.concat(logEntries); 73 for (var i = 0; i < this.observers_.length; ++i) { 74 this.observers_[i].onReceivedLogEntries(logEntries); 75 } 76 77 // Check that we haven't grown too big. If so, toss out older events. 78 if (this.getNumCapturedEvents() > this.hardLimit_) { 79 var originalEvents = this.capturedEvents_; 80 this.deleteAllLogEntries(); 81 // Delete the oldest events until we reach the soft limit. 82 originalEvents.splice(0, originalEvents.length - this.softLimit_); 83 this.addLogEntries(originalEvents); 84 } 85 }, 86 87 /** 88 * Adds a listener of log entries. |observer| will be called back when new 89 * log data arrives or all entries are deleted: 90 * 91 * observer.onReceivedLogEntries(entries) 92 * observer.onAllLogEntriesDeleted() 93 */ 94 addLogEntryObserver: function(observer) { 95 this.observers_.push(observer); 96 }, 97 98 /** 99 * Set bounds on the maximum number of events that will be tracked. This 100 * helps to bound the total amount of memory usage, since otherwise 101 * long-running capture sessions can exhaust the renderer's memory and 102 * crash. 103 * 104 * Once |hardLimit| number of events have been captured we do a garbage 105 * collection and toss out old events, bringing our count down to 106 * |softLimit|. 107 * 108 * To log observers this will look like all the events got deleted, and 109 * then subsequently a bunch of new events were received. In other words, it 110 * behaves the same as if the user had simply started logging a bit later 111 * in time! 112 */ 113 setLimits: function(softLimit, hardLimit) { 114 if (hardLimit != Infinity && softLimit >= hardLimit) 115 throw 'hardLimit must be greater than softLimit'; 116 117 this.softLimit_ = softLimit; 118 this.hardLimit_ = hardLimit; 119 } 120 }; 121 122 return EventsTracker; 123})(); 124