blob: 20ab6b227db2254c6ea77ab54670ec58b2199b84 [file] [log] [blame]
# Copyright 2020 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.
"""Creates and manages test runner log file objects.
Provides a context manager object for use in a with statement
and a module level FileStreamFor function for use by clients.
"""
import collections
import multiprocessing
import os
from symbolizer import RunSymbolizer
SYMBOLIZED_SUFFIX = '.symbolized'
_RunnerLogEntry = collections.namedtuple(
'_RunnerLogEntry', ['name', 'log_file', 'path', 'symbolize'])
# Module singleton variable.
_instance = None
class RunnerLogManager(object):
""" Runner logs object for use in a with statement."""
def __init__(self, log_dir, build_ids_files):
global _instance
if _instance:
raise Exception('Only one RunnerLogManager can be instantiated')
self._log_dir = log_dir
self._build_ids_files = build_ids_files
self._runner_logs = []
if self._log_dir and not os.path.isdir(self._log_dir):
os.makedirs(self._log_dir)
_instance = self
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
pool = multiprocessing.Pool(4)
for log_entry in self._runner_logs:
pool.apply_async(_FinalizeLog, (log_entry, self._build_ids_files))
pool.close()
pool.join()
_instance = None
def _FileStreamFor(self, name, symbolize):
if any(elem.name == name for elem in self._runner_logs):
raise Exception('RunnerLogManager can only open "%s" once' % name)
path = os.path.join(self._log_dir, name) if self._log_dir else os.devnull
log_file = open(path, 'w')
self._runner_logs.append(_RunnerLogEntry(name, log_file, path, symbolize))
return log_file
def _FinalizeLog(log_entry, build_ids_files):
log_entry.log_file.close()
if log_entry.symbolize:
input_file = open(log_entry.path, 'r')
output_file = open(log_entry.path + SYMBOLIZED_SUFFIX, 'w')
proc = RunSymbolizer(input_file, output_file, build_ids_files)
proc.wait()
output_file.close()
input_file.close()
def IsEnabled():
"""Returns True if the RunnerLogManager has been created, or False if not."""
return _instance is not None and _instance._log_dir is not None
def FileStreamFor(name, symbolize=False):
"""Opens a test runner file stream in the test runner log directory.
If no test runner log directory is specified, output is discarded.
name: log file name
symbolize: if True, make a symbolized copy of the log after closing it.
Returns an opened log file object."""
return _instance._FileStreamFor(name, symbolize) if IsEnabled() else open(
os.devnull, 'w')