blob: 740e87f46fa1289de5ad0b2d61effd6afcb81537 [file] [log] [blame]
# Copyright 2021 The Chromium OS 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 checking doesn't always work
# pylint: disable=import-error
"""Console that logs output of each command to a file in log/"""
import atexit
import code
from datetime import datetime
import os
import readline
import rlcompleter
import sys
import sh
# Python's default history path
histfile = os.path.expanduser('~/.python_history')
def save_history():
"""appends command history to the history file"""
readline.set_history_length(10000)
readline.write_history_file(histfile)
class Logger:
"""Splits stdout into stdout and a file"""
def __init__(self):
sh.mkdir('-p', 'log/triage/')
ts = datetime.now().strftime('%d-%m-%Y_%H-%M-%S')
filename = ts + '.log'
if os.path.exists('log/latest'):
sh.rm('log/latest')
sh.ln('-s', filename, 'log/latest')
self.terminal = sys.stdout
self.log = open('log/' + filename, 'w')
def write(self, message):
"""Forwards write() call to self.terminal and self.log"""
self.terminal.write(message)
self.log.write(message)
def flush(self):
"""Forwards flush() call to self.terminal and self.log"""
self.terminal.flush()
self.log.flush()
class LoggingConsole(code.InteractiveConsole):
"""code.InteractiveConsole that logs console output"""
def __init__(self, local=None):
code.InteractiveConsole.__init__(self, local)
self.logger = Logger()
try:
readline.read_history_file(histfile)
atexit.register(save_history)
except FileNotFoundError:
pass
readline.set_completer(rlcompleter.Completer(local).complete)
readline.parse_and_bind('tab: complete')
def push(self, line):
"""temporarily subsistute a Logger() instance before forwarding the push() call
This is necessary because the InteractiveConsole will refuse to support history
if sys.stdout isn't the default value.
"""
sys.stdout = self.logger
super().push(line)
sys.stdout = self.logger.terminal