blob: cad3f306993b8d74a2558ed1fe72ff947b6d5674 [file] [log] [blame]
# Copyright (c) 2016 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Represents the trace of a page load."""
import datetime
try:
import ujson as json
except ImportError:
import json
import time
import devtools_monitor
import page_track
import request_track
import tracing_track
class LoadingTrace(object):
"""Represents the trace of a page load."""
_URL_KEY = 'url'
_METADATA_KEY = 'metadata'
_PAGE_KEY = 'page_track'
_REQUEST_KEY = 'request_track'
_TRACING_KEY = 'tracing_track'
def __init__(self, url, metadata, page, request, track):
"""Initializes a loading trace instance.
Args:
url: (str) URL that has been loaded
metadata: (dict) Metadata associated with the load.
page: (PageTrack) instance of PageTrack.
request: (RequestTrack) instance of RequestTrack.
track: (TracingTrack) instance of TracingTrack.
"""
self.url = url
self.metadata = metadata
self.page_track = page
self.request_track = request
self._tracing_track = track
self._tracing_json_str = None
def ToJsonDict(self):
"""Returns a dictionary representing this instance."""
result = {self._URL_KEY: self.url, self._METADATA_KEY: self.metadata,
self._PAGE_KEY: self.page_track.ToJsonDict(),
self._REQUEST_KEY: self.request_track.ToJsonDict(),
self._TRACING_KEY: (self.tracing_track.ToJsonDict()
if self.tracing_track else None)}
return result
def ToJsonFile(self, json_path):
"""Save a json file representing this instance."""
json_dict = self.ToJsonDict()
with open(json_path, 'w') as output_file:
json.dump(json_dict, output_file)
@classmethod
def FromJsonDict(cls, json_dict):
"""Returns an instance from a dictionary returned by ToJsonDict()."""
keys = (cls._URL_KEY, cls._METADATA_KEY, cls._PAGE_KEY, cls._REQUEST_KEY,
cls._TRACING_KEY)
assert all(key in json_dict for key in keys)
page = page_track.PageTrack.FromJsonDict(json_dict[cls._PAGE_KEY])
request = request_track.RequestTrack.FromJsonDict(
json_dict[cls._REQUEST_KEY])
track = tracing_track.TracingTrack.FromJsonDict(
json_dict[cls._TRACING_KEY])
return LoadingTrace(json_dict[cls._URL_KEY], json_dict[cls._METADATA_KEY],
page, request, track)
@classmethod
def FromJsonFile(cls, json_path):
"""Returns an instance from a json file saved by ToJsonFile()."""
with open(json_path) as input_file:
return cls.FromJsonDict(json.load(input_file))
@classmethod
def RecordUrlNavigation(
cls, url, connection, chrome_metadata, categories,
timeout_seconds=devtools_monitor.DEFAULT_TIMEOUT_SECONDS,
stop_delay_multiplier=0):
"""Create a loading trace by using controller to fetch url.
Args:
url: (str) url to fetch.
connection: An opened devtools connection.
chrome_metadata: Dictionary of chrome metadata.
categories: as in tracing_track.TracingTrack
timeout_seconds: monitoring connection timeout in seconds.
stop_delay_multiplier: How long to wait after page load completed before
tearing down, relative to the time it took to reach the page load to
complete.
Returns:
LoadingTrace instance.
"""
page = page_track.PageTrack(connection)
request = request_track.RequestTrack(connection)
trace = tracing_track.TracingTrack(connection, categories)
start_date_str = datetime.datetime.utcnow().isoformat()
seconds_since_epoch=time.time()
connection.MonitorUrl(url,
timeout_seconds=timeout_seconds,
stop_delay_multiplier=stop_delay_multiplier)
trace = cls(url, chrome_metadata, page, request, trace)
trace.metadata.update(date=start_date_str,
seconds_since_epoch=seconds_since_epoch)
return trace
@property
def tracing_track(self):
if not self._tracing_track:
self._RestoreTracingTrack()
return self._tracing_track
def Slim(self):
"""Slims the memory usage of a trace by dropping the TraceEvents from it.
The tracing track is restored on-demand when accessed.
"""
self._tracing_json_str = json.dumps(self._tracing_track.ToJsonDict())
self._tracing_track = None
def _RestoreTracingTrack(self):
if not self._tracing_json_str:
return None
self._tracing_track = tracing_track.TracingTrack.FromJsonDict(
json.loads(self._tracing_json_str))
self._tracing_json_str = None