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.
5 var SourceEntry
= (function() {
9 * A SourceEntry gathers all log entries with the same source.
13 function SourceEntry(logEntry
, maxPreviousSourceId
) {
14 this.maxPreviousSourceId_
= maxPreviousSourceId
;
16 this.description_
= '';
18 // Set to true on most net errors.
19 this.isError_
= false;
21 // If the first entry is a BEGIN_PHASE, set to false.
22 // Set to true when an END_PHASE matching the first entry is encountered.
23 this.isInactive_
= true;
25 if (logEntry
.phase
== EventPhase
.PHASE_BEGIN
)
26 this.isInactive_
= false;
28 this.update(logEntry
);
31 SourceEntry
.prototype = {
32 update: function(logEntry
) {
33 // Only the last event should have the same type first event,
34 if (!this.isInactive_
&&
35 logEntry
.phase
== EventPhase
.PHASE_END
&&
36 logEntry
.type
== this.entries_
[0].type
) {
37 this.isInactive_
= true;
40 // If we have a net error code, update |this.isError_| if appropriate.
41 if (logEntry
.params
) {
42 var netErrorCode
= logEntry
.params
.net_error
;
43 // Skip both cases where netErrorCode is undefined, and cases where it
44 // is 0, indicating no actual error occurred.
46 // Ignore error code caused by not finding an entry in the cache.
47 if (logEntry
.type
!= EventType
.HTTP_CACHE_OPEN_ENTRY
||
48 netErrorCode
!= NetError
.ERR_FAILED
) {
54 var prevStartEntry
= this.getStartEntry_();
55 this.entries_
.push(logEntry
);
56 var curStartEntry
= this.getStartEntry_();
58 // If we just got the first entry for this source.
59 if (prevStartEntry
!= curStartEntry
)
60 this.updateDescription_();
63 updateDescription_: function() {
64 var e
= this.getStartEntry_();
65 this.description_
= '';
69 if (e
.source
.type
== EventSourceType
.NONE
) {
70 // NONE is what we use for global events that aren't actually grouped
71 // by a "source ID", so we will just stringize the event's type.
72 this.description_
= EventTypeNames
[e
.type
];
76 if (e
.params
== undefined) {
80 switch (e
.source
.type
) {
81 case EventSourceType
.URL_REQUEST
:
82 // TODO(ricea): Remove SOCKET_STREAM after M41 is released.
83 case EventSourceType
.SOCKET_STREAM
:
84 case EventSourceType
.HTTP_STREAM_JOB
:
85 this.description_
= e
.params
.url
;
87 case EventSourceType
.CONNECT_JOB
:
88 this.description_
= e
.params
.group_name
;
90 case EventSourceType
.HOST_RESOLVER_IMPL_JOB
:
91 case EventSourceType
.HOST_RESOLVER_IMPL_PROC_TASK
:
92 this.description_
= e
.params
.host
;
94 case EventSourceType
.DISK_CACHE_ENTRY
:
95 case EventSourceType
.MEMORY_CACHE_ENTRY
:
96 this.description_
= e
.params
.key
;
98 case EventSourceType
.QUIC_SESSION
:
99 if (e
.params
.host
!= undefined)
100 this.description_
= e
.params
.host
;
102 case EventSourceType
.HTTP2_SESSION
:
104 this.description_
= e
.params
.host
+ ' (' + e
.params
.proxy
+ ')';
106 case EventSourceType
.HTTP_PIPELINED_CONNECTION
:
107 if (e
.params
.host_and_port
)
108 this.description_
= e
.params
.host_and_port
;
110 case EventSourceType
.SOCKET
:
111 case EventSourceType
.PROXY_CLIENT_SOCKET
:
112 // Use description of parent source, if any.
113 if (e
.params
.source_dependency
!= undefined) {
114 var parentId
= e
.params
.source_dependency
.id
;
116 SourceTracker
.getInstance().getDescription(parentId
);
119 case EventSourceType
.UDP_SOCKET
:
120 if (e
.params
.address
!= undefined) {
121 this.description_
= e
.params
.address
;
122 // If the parent of |this| is a HOST_RESOLVER_IMPL_JOB, use
123 // '<DNS Server IP> [<host we're resolving>]'.
124 if (this.entries_
[0].type
== EventType
.SOCKET_ALIVE
&&
125 this.entries_
[0].params
&&
126 this.entries_
[0].params
.source_dependency
!= undefined) {
127 var parentId
= this.entries_
[0].params
.source_dependency
.id
;
128 var parent
= SourceTracker
.getInstance().getSourceEntry(parentId
);
130 parent
.getSourceType() ==
131 EventSourceType
.HOST_RESOLVER_IMPL_JOB
&&
132 parent
.getDescription().length
> 0) {
133 this.description_
+= ' [' + parent
.getDescription() + ']';
138 case EventSourceType
.ASYNC_HOST_RESOLVER_REQUEST
:
139 case EventSourceType
.DNS_TRANSACTION
:
140 this.description_
= e
.params
.hostname
;
142 case EventSourceType
.DOWNLOAD
:
144 case EventType
.DOWNLOAD_FILE_RENAMED
:
145 this.description_
= e
.params
.new_filename
;
147 case EventType
.DOWNLOAD_FILE_OPENED
:
148 this.description_
= e
.params
.file_name
;
150 case EventType
.DOWNLOAD_ITEM_ACTIVE
:
151 this.description_
= e
.params
.file_name
;
155 case EventSourceType
.FILESTREAM
:
156 this.description_
= e
.params
.file_name
;
158 case EventSourceType
.IPV6_PROBE_JOB
:
159 if (e
.type
== EventType
.IPV6_PROBE_RUNNING
&&
160 e
.phase
== EventPhase
.PHASE_END
) {
161 this.description_
= e
.params
.ipv6_supported
? 'IPv6 Supported' :
162 'IPv6 Not Supported';
167 if (this.description_
== undefined)
168 this.description_
= '';
172 * Returns a description for this source log stream, which will be displayed
173 * in the list view. Most often this is a URL that identifies the request,
174 * or a hostname for a connect job, etc...
176 getDescription: function() {
177 return this.description_
;
181 * Returns the starting entry for this source. Conceptually this is the
182 * first entry that was logged to this source. However, we skip over the
183 * TYPE_REQUEST_ALIVE entries which wrap TYPE_URL_REQUEST_START_JOB
186 getStartEntry_: function() {
187 if (this.entries_
.length
< 1)
189 if (this.entries_
[0].source
.type
== EventSourceType
.FILESTREAM
) {
190 var e
= this.findLogEntryByType_(EventType
.FILE_STREAM_OPEN
);
194 if (this.entries_
[0].source
.type
== EventSourceType
.DOWNLOAD
) {
195 // If any rename occurred, use the last name
196 e
= this.findLastLogEntryStartByType_(
197 EventType
.DOWNLOAD_FILE_RENAMED
);
200 // Otherwise, if the file was opened, use that name
201 e
= this.findLogEntryByType_(EventType
.DOWNLOAD_FILE_OPENED
);
204 // History items are never opened, so use the activation info
205 e
= this.findLogEntryByType_(EventType
.DOWNLOAD_ITEM_ACTIVE
);
209 if (this.entries_
.length
>= 2) {
210 // Needed for compatability with log dumps prior to M26.
211 // TODO(mmenke): Remove this.
212 if (this.entries_
[0].type
== EventType
.SOCKET_POOL_CONNECT_JOB
&&
213 this.entries_
[0].params
== undefined) {
214 return this.entries_
[1];
216 if (this.entries_
[1].type
== EventType
.UDP_CONNECT
)
217 return this.entries_
[1];
218 if (this.entries_
[0].type
== EventType
.REQUEST_ALIVE
&&
219 this.entries_
[0].params
== undefined) {
221 // Skip over delegate events for URL_REQUESTs.
222 for (; startIndex
+ 1 < this.entries_
.length
; ++startIndex
) {
223 var type
= this.entries_
[startIndex
].type
;
224 if (type
!= EventType
.URL_REQUEST_DELEGATE
&&
225 type
!= EventType
.DELEGATE_INFO
) {
229 return this.entries_
[startIndex
];
231 if (this.entries_
[1].type
== EventType
.IPV6_PROBE_RUNNING
)
232 return this.entries_
[1];
234 return this.entries_
[0];
238 * Returns the first entry with the specified type, or undefined if not
241 findLogEntryByType_: function(type
) {
242 for (var i
= 0; i
< this.entries_
.length
; ++i
) {
243 if (this.entries_
[i
].type
== type
) {
244 return this.entries_
[i
];
251 * Returns the beginning of the last entry with the specified type, or
252 * undefined if not found.
254 findLastLogEntryStartByType_: function(type
) {
255 for (var i
= this.entries_
.length
- 1; i
>= 0; --i
) {
256 if (this.entries_
[i
].type
== type
) {
257 if (this.entries_
[i
].phase
!= EventPhase
.PHASE_END
)
258 return this.entries_
[i
];
264 getLogEntries: function() {
265 return this.entries_
;
268 getSourceTypeString: function() {
269 return EventSourceTypeNames
[this.entries_
[0].source
.type
];
272 getSourceType: function() {
273 return this.entries_
[0].source
.type
;
276 getSourceId: function() {
277 return this.entries_
[0].source
.id
;
281 * Returns the largest source ID seen before this object was received.
282 * Used only for sorting SourceEntries without a source by source ID.
284 getMaxPreviousEntrySourceId: function() {
285 return this.maxPreviousSourceId_
;
288 isInactive: function() {
289 return this.isInactive_
;
292 isError: function() {
293 return this.isError_
;
297 * Returns time ticks of first event.
299 getStartTicks: function() {
300 return this.entries_
[0].time
;
304 * Returns time of last event if inactive. Returns current time otherwise.
305 * Returned time is a "time ticks" value.
307 getEndTicks: function() {
308 if (!this.isInactive_
)
309 return timeutil
.getCurrentTimeTicks();
310 return this.entries_
[this.entries_
.length
- 1].time
;
314 * Returns the time between the first and last events with a matching
315 * source ID. If source is still active, uses the current time for the
318 getDuration: function() {
319 var startTime
= this.getStartTicks();
320 var endTime
= this.getEndTicks();
321 return endTime
- startTime
;
325 * Prints descriptive text about |entries_| to a new node added to the end
328 printAsText: function(parent
) {
329 var tablePrinter
= this.createTablePrinter();
331 // Format the table for fixed-width text.
332 tablePrinter
.toText(0, parent
);
336 * Creates a table printer for the SourceEntry.
338 createTablePrinter: function() {
339 return createLogEntryTablePrinter(
341 SourceTracker
.getInstance().getPrivacyStripping(),
342 SourceTracker
.getInstance().getUseRelativeTimes() ?
343 timeutil
.getBaseTime() : 0,
344 Constants
.clientInfo
.numericDate
);