| Index: build/android/pylib/android/logdog_logcat_monitor.py
 | 
| diff --git a/build/android/pylib/android/logdog_logcat_monitor.py b/build/android/pylib/android/logdog_logcat_monitor.py
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..788f48285392c948b6d271eaf26987f2426718de
 | 
| --- /dev/null
 | 
| +++ b/build/android/pylib/android/logdog_logcat_monitor.py
 | 
| @@ -0,0 +1,89 @@
 | 
| +# Copyright 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.
 | 
| +
 | 
| +import os
 | 
| +import logging
 | 
| +import sys
 | 
| +
 | 
| +from devil.android import logcat_monitor
 | 
| +from devil.utils import reraiser_thread
 | 
| +from pylib import constants
 | 
| +
 | 
| +sys.path.insert(0, os.path.abspath(os.path.join(
 | 
| +    constants.DIR_SOURCE_ROOT, 'tools', 'swarming_client')))
 | 
| +from libs.logdog import bootstrap # pylint: disable=import-error
 | 
| +
 | 
| +class LogdogLogcatMonitor(logcat_monitor.LogcatMonitor):
 | 
| +  """Logcat monitor that writes logcat to a logdog stream.
 | 
| +  The logdog stream client will return a url, where contains the logcat.
 | 
| +  """
 | 
| +  def __init__(self, adb, stream_name, clear=True, filter_specs=None):
 | 
| +    super(LogdogLogcatMonitor, self).__init__(adb, clear, filter_specs)
 | 
| +    self._logcat_url = ''
 | 
| +    self._logdog_stream = None
 | 
| +    self._stream_client = None
 | 
| +    self._stream_name = stream_name
 | 
| +    try:
 | 
| +      self._stream_client = bootstrap.ButlerBootstrap.probe().stream_client()
 | 
| +      self._logdog_stream = self._stream_client.open_text(self._stream_name)
 | 
| +    except bootstrap.NotBootstrappedError as e:
 | 
| +      logging.exception(
 | 
| +          'Error not bootstrapped. Failed to start logdog: %s', e)
 | 
| +    except (KeyError, ValueError) as e:
 | 
| +      logging.exception('Error when creating stream_client/stream: %s.', e)
 | 
| +
 | 
| +  def GetLogcatURL(self):
 | 
| +    """Return logcat url.
 | 
| +
 | 
| +    The default logcat url is '', if failed to create stream_client.
 | 
| +    """
 | 
| +    return self._logcat_url
 | 
| +
 | 
| +  def Stop(self):
 | 
| +    """Stops the logcat monitor.
 | 
| +
 | 
| +    Close the logdog stream as well.
 | 
| +    """
 | 
| +    super(LogdogLogcatMonitor, self)._StopRecording()
 | 
| +    if self._logdog_stream:
 | 
| +      try:
 | 
| +        self._logcat_url = self._stream_client.get_viewer_url(self._stream_name)
 | 
| +      except (KeyError, ValueError) as e:
 | 
| +        logging.exception('Error cannot get viewer url: %s', e)
 | 
| +      self._logdog_stream.close()
 | 
| +
 | 
| +  def Start(self):
 | 
| +    """Starts the logdog logcat monitor.
 | 
| +
 | 
| +    Clears the logcat if |clear| was set in |__init__|.
 | 
| +    """
 | 
| +    if self._clear:
 | 
| +      self._adb.Logcat(clear=True)
 | 
| +    self._StartRecording()
 | 
| +
 | 
| +  def _StartRecording(self):
 | 
| +    """Starts recording logcat to file.
 | 
| +
 | 
| +    Write logcat to stream at the same time.
 | 
| +    """
 | 
| +    def record_to_stream():
 | 
| +      if self._logdog_stream:
 | 
| +        for data in self._adb.Logcat(filter_specs=self._filter_specs,
 | 
| +                                     logcat_format='threadtime'):
 | 
| +          if self._stop_recording_event.isSet():
 | 
| +            return
 | 
| +          self._logdog_stream.write(data + '\n')
 | 
| +
 | 
| +    self._stop_recording_event.clear()
 | 
| +    if not self._record_thread:
 | 
| +      self._record_thread = reraiser_thread.ReraiserThread(record_to_stream)
 | 
| +      self._record_thread.start()
 | 
| +
 | 
| +  def Close(self):
 | 
| +    """Override parent's close method."""
 | 
| +    pass
 | 
| +
 | 
| +  def __del__(self):
 | 
| +    """Override parent's delete method."""
 | 
| +    pass
 | 
| 
 |