1 # Copyright 2013 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.
7 from telemetry.core.backends.chrome import inspector_websocket
8 from telemetry.core.platform import tracing_options
11 class TracingUnsupportedException(Exception):
15 class TracingTimeoutException(Exception):
18 class TracingHasNotRunException(Exception):
22 class TracingBackend(object):
23 def __init__(self, devtools_port, chrome_browser_backend):
24 self._inspector_websocket = inspector_websocket.InspectorWebsocket(
25 self._NotificationHandler,
28 self._inspector_websocket.Connect(
29 'ws://127.0.0.1:%i/devtools/browser' % devtools_port)
30 self._tracing_data = []
31 self._is_tracing_running = False
32 self._chrome_browser_backend = chrome_browser_backend
35 def is_tracing_running(self):
36 return self._is_tracing_running
38 def StartTracing(self, trace_options, custom_categories=None, timeout=10):
39 """ Starts tracing on the first call and returns True. Returns False
40 and does nothing on subsequent nested calls.
42 if self.is_tracing_running:
44 # Reset collected tracing data from previous tracing calls.
45 self._tracing_data = []
46 self._CheckNotificationSupported()
47 #TODO(nednguyen): remove this when the stable branch pass 2118.
48 if (trace_options.record_mode == tracing_options.RECORD_AS_MUCH_AS_POSSIBLE
49 and self._chrome_browser_backend.chrome_branch_number
50 and self._chrome_browser_backend.chrome_branch_number < 2118):
52 'Cannot use %s tracing mode on chrome browser with branch version %i,'
53 ' (<2118) fallback to use %s tracing mode' % (
54 trace_options.record_mode,
55 self._chrome_browser_backend.chrome_branch_number,
56 tracing_options.RECORD_UNTIL_FULL))
57 trace_options.record_mode = tracing_options.RECORD_UNTIL_FULL
58 req = {'method': 'Tracing.start'}
60 m = {tracing_options.RECORD_UNTIL_FULL: 'record-until-full',
61 tracing_options.RECORD_AS_MUCH_AS_POSSIBLE:
62 'record-as-much-as-possible'}
63 req['params']['options'] = m[trace_options.record_mode]
65 req['params']['categories'] = custom_categories
66 self._inspector_websocket.SyncRequest(req, timeout)
67 self._is_tracing_running = True
70 def StopTracing(self, timeout=30):
71 """ Stops tracing and returns the raw json trace result. It this is called
72 after tracing has been stopped, trace data from the last tracing run is
75 if not self.is_tracing_running:
76 if not self._tracing_data:
77 raise TracingHasNotRunException()
79 return self._tracing_data
80 req = {'method': 'Tracing.end'}
81 self._inspector_websocket.SendAndIgnoreResponse(req)
82 # After Tracing.end, chrome browser will send asynchronous notifications
83 # containing trace data. This is until Tracing.tracingComplete is sent,
84 # which means there is no trace buffers pending flush.
86 self._inspector_websocket.DispatchNotificationsUntilDone(timeout)
88 inspector_websocket.DispatchNotificationsUntilDoneTimeoutException \
90 raise TracingTimeoutException(
91 'Trace data was not fully received due to timeout after %s '
92 'seconds. If the trace data is big, you may want to increase the '
93 'time out amount.' % err.elapsed_time)
94 self._is_tracing_running = False
95 return self._tracing_data
97 def _ErrorHandler(self, elapsed):
98 logging.error('Unrecoverable error after %ds reading tracing response.',
102 def _NotificationHandler(self, res):
103 if 'Tracing.dataCollected' == res.get('method'):
104 value = res.get('params', {}).get('value')
105 if type(value) in [str, unicode]:
106 self._tracing_data.append(value)
107 elif type(value) is list:
108 self._tracing_data.extend(value)
110 logging.warning('Unexpected type in tracing data')
111 elif 'Tracing.tracingComplete' == res.get('method'):
115 self._inspector_websocket.Disconnect()
117 def _CheckNotificationSupported(self):
118 """Ensures we're running against a compatible version of chrome."""
119 req = {'method': 'Tracing.hasCompleted'}
120 res = self._inspector_websocket.SyncRequest(req)
121 if res.get('response'):
122 raise TracingUnsupportedException(
123 'Tracing not supported for this browser')