xref: /aosp_15_r20/external/angle/build/fuchsia/test/log_manager.py (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1*8975f5c5SAndroid Build Coastguard Worker# Copyright 2022 The Chromium Authors
2*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be
3*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file.
4*8975f5c5SAndroid Build Coastguard Worker"""Reads log data from a device."""
5*8975f5c5SAndroid Build Coastguard Worker
6*8975f5c5SAndroid Build Coastguard Workerimport os
7*8975f5c5SAndroid Build Coastguard Workerimport subprocess
8*8975f5c5SAndroid Build Coastguard Workerimport sys
9*8975f5c5SAndroid Build Coastguard Worker
10*8975f5c5SAndroid Build Coastguard Workerfrom contextlib import AbstractContextManager
11*8975f5c5SAndroid Build Coastguard Workerfrom typing import Iterable, Optional, TextIO
12*8975f5c5SAndroid Build Coastguard Worker
13*8975f5c5SAndroid Build Coastguard Workerfrom common import run_continuous_ffx_command
14*8975f5c5SAndroid Build Coastguard Workerfrom ffx_integration import run_symbolizer
15*8975f5c5SAndroid Build Coastguard Worker
16*8975f5c5SAndroid Build Coastguard Worker
17*8975f5c5SAndroid Build Coastguard Workerclass LogManager(AbstractContextManager):
18*8975f5c5SAndroid Build Coastguard Worker    """Handles opening and closing file streams for logging purposes."""
19*8975f5c5SAndroid Build Coastguard Worker
20*8975f5c5SAndroid Build Coastguard Worker    def __init__(self, logs_dir: Optional[str]) -> None:
21*8975f5c5SAndroid Build Coastguard Worker        self._logs_dir = logs_dir
22*8975f5c5SAndroid Build Coastguard Worker
23*8975f5c5SAndroid Build Coastguard Worker        # A dictionary with the log file path as the key and a file stream as
24*8975f5c5SAndroid Build Coastguard Worker        # value.
25*8975f5c5SAndroid Build Coastguard Worker        self._log_files = {}
26*8975f5c5SAndroid Build Coastguard Worker        self._log_procs = []
27*8975f5c5SAndroid Build Coastguard Worker        self._scoped_ffx_log = None
28*8975f5c5SAndroid Build Coastguard Worker
29*8975f5c5SAndroid Build Coastguard Worker    def __enter__(self):
30*8975f5c5SAndroid Build Coastguard Worker        return self
31*8975f5c5SAndroid Build Coastguard Worker
32*8975f5c5SAndroid Build Coastguard Worker    def is_logging_enabled(self) -> bool:
33*8975f5c5SAndroid Build Coastguard Worker        """Check whether logging is turned on."""
34*8975f5c5SAndroid Build Coastguard Worker
35*8975f5c5SAndroid Build Coastguard Worker        return self._logs_dir is not None
36*8975f5c5SAndroid Build Coastguard Worker
37*8975f5c5SAndroid Build Coastguard Worker    def add_log_process(self, process: subprocess.Popen) -> None:
38*8975f5c5SAndroid Build Coastguard Worker        """Register a logging process to LogManager to be killed at LogManager
39*8975f5c5SAndroid Build Coastguard Worker        teardown."""
40*8975f5c5SAndroid Build Coastguard Worker
41*8975f5c5SAndroid Build Coastguard Worker        self._log_procs.append(process)
42*8975f5c5SAndroid Build Coastguard Worker
43*8975f5c5SAndroid Build Coastguard Worker    def open_log_file(self, log_file_name: str) -> TextIO:
44*8975f5c5SAndroid Build Coastguard Worker        """Open a file stream with log_file_name in the logs directory."""
45*8975f5c5SAndroid Build Coastguard Worker
46*8975f5c5SAndroid Build Coastguard Worker        assert self._logs_dir, 'Logging directory is not specified.'
47*8975f5c5SAndroid Build Coastguard Worker        log_file_path = os.path.join(self._logs_dir, log_file_name)
48*8975f5c5SAndroid Build Coastguard Worker        log_file = open(log_file_path, 'w', buffering=1)
49*8975f5c5SAndroid Build Coastguard Worker        self._log_files[log_file_path] = log_file
50*8975f5c5SAndroid Build Coastguard Worker        return log_file
51*8975f5c5SAndroid Build Coastguard Worker
52*8975f5c5SAndroid Build Coastguard Worker    def __exit__(self, exc_type, exc_value, traceback):
53*8975f5c5SAndroid Build Coastguard Worker        """Stop all active logging instances."""
54*8975f5c5SAndroid Build Coastguard Worker        for proc in self._log_procs:
55*8975f5c5SAndroid Build Coastguard Worker            proc.kill()
56*8975f5c5SAndroid Build Coastguard Worker        for log in self._log_files.values():
57*8975f5c5SAndroid Build Coastguard Worker            log.close()
58*8975f5c5SAndroid Build Coastguard Worker        return False
59*8975f5c5SAndroid Build Coastguard Worker
60*8975f5c5SAndroid Build Coastguard Worker
61*8975f5c5SAndroid Build Coastguard Workerdef start_system_log(log_manager: LogManager,
62*8975f5c5SAndroid Build Coastguard Worker                     log_to_stdout: bool,
63*8975f5c5SAndroid Build Coastguard Worker                     pkg_paths: Optional[Iterable[str]] = None,
64*8975f5c5SAndroid Build Coastguard Worker                     log_args: Optional[Iterable[str]] = None,
65*8975f5c5SAndroid Build Coastguard Worker                     target_id: Optional[str] = None) -> None:
66*8975f5c5SAndroid Build Coastguard Worker    """
67*8975f5c5SAndroid Build Coastguard Worker    Start system logging.
68*8975f5c5SAndroid Build Coastguard Worker
69*8975f5c5SAndroid Build Coastguard Worker    Args:
70*8975f5c5SAndroid Build Coastguard Worker        log_manager: A LogManager class that manages the log file and process.
71*8975f5c5SAndroid Build Coastguard Worker        log_to_stdout: If set to True, print logs directly to stdout.
72*8975f5c5SAndroid Build Coastguard Worker        pkg_paths: Path to the packages
73*8975f5c5SAndroid Build Coastguard Worker        log_args: Arguments forwarded to `ffx log` command.
74*8975f5c5SAndroid Build Coastguard Worker        target_id: Specify a target to use.
75*8975f5c5SAndroid Build Coastguard Worker    """
76*8975f5c5SAndroid Build Coastguard Worker
77*8975f5c5SAndroid Build Coastguard Worker    if not log_manager.is_logging_enabled() and not log_to_stdout:
78*8975f5c5SAndroid Build Coastguard Worker        return
79*8975f5c5SAndroid Build Coastguard Worker    symbol_paths = None
80*8975f5c5SAndroid Build Coastguard Worker    if pkg_paths:
81*8975f5c5SAndroid Build Coastguard Worker        symbol_paths = []
82*8975f5c5SAndroid Build Coastguard Worker
83*8975f5c5SAndroid Build Coastguard Worker        # Locate debug symbols for each package.
84*8975f5c5SAndroid Build Coastguard Worker        for pkg_path in pkg_paths:
85*8975f5c5SAndroid Build Coastguard Worker            assert os.path.isfile(pkg_path), '%s does not exist' % pkg_path
86*8975f5c5SAndroid Build Coastguard Worker            symbol_paths.append(
87*8975f5c5SAndroid Build Coastguard Worker                os.path.join(os.path.dirname(pkg_path), 'ids.txt'))
88*8975f5c5SAndroid Build Coastguard Worker
89*8975f5c5SAndroid Build Coastguard Worker    if log_to_stdout:
90*8975f5c5SAndroid Build Coastguard Worker        system_log = sys.stdout
91*8975f5c5SAndroid Build Coastguard Worker    else:
92*8975f5c5SAndroid Build Coastguard Worker        system_log = log_manager.open_log_file('system_log')
93*8975f5c5SAndroid Build Coastguard Worker    log_cmd = ['log', '--symbolize', 'off', '--no-color']
94*8975f5c5SAndroid Build Coastguard Worker    if log_args:
95*8975f5c5SAndroid Build Coastguard Worker        log_cmd.extend(log_args)
96*8975f5c5SAndroid Build Coastguard Worker    if symbol_paths:
97*8975f5c5SAndroid Build Coastguard Worker        log_proc = run_continuous_ffx_command(log_cmd,
98*8975f5c5SAndroid Build Coastguard Worker                                              target_id,
99*8975f5c5SAndroid Build Coastguard Worker                                              stdout=subprocess.PIPE)
100*8975f5c5SAndroid Build Coastguard Worker        log_manager.add_log_process(log_proc)
101*8975f5c5SAndroid Build Coastguard Worker        log_manager.add_log_process(
102*8975f5c5SAndroid Build Coastguard Worker            run_symbolizer(symbol_paths, log_proc.stdout, system_log))
103*8975f5c5SAndroid Build Coastguard Worker    else:
104*8975f5c5SAndroid Build Coastguard Worker        log_manager.add_log_process(
105*8975f5c5SAndroid Build Coastguard Worker            run_continuous_ffx_command(log_cmd, target_id, stdout=system_log))
106