nubia/internal/io/session_logger.py (40 lines of code) (raw):
#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates.
# All rights reserved.
#
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree.
import re
import sys
import threading
from contextlib import contextmanager
class SessionLogger:
"""
SessionLogger is used to intercept stdout content and duplicates it to
a session log file.
Inspired from prompt_toolkit.StdoutProxy but without the buffering.
"""
def __init__(self, file):
self._log_file = file
self._lock = threading.RLock()
self.original_stdout = sys.stdout
# errors/encoding attribute for compatibility with sys.stdout.
self.errors = sys.stdout.errors
self.encoding = sys.stdout.encoding
def path(self):
return self._log_file.name
def log_command(self, cmd):
cmd = self._strip_ansii_colors(cmd)
with self._lock:
self._log_file.write(f"\n> {cmd}\n")
def write(self, data):
with self._lock:
self.original_stdout.write(data)
self._log_file.write(self._strip_ansii_colors(data))
def flush(self):
with self._lock:
self.original_stdout.flush()
self._log_file.flush()
def _strip_ansii_colors(self, text):
return re.sub("\x1b\\[.+?m", "", text)
def isatty(self):
return self.original_stdout.isatty()
def fileno(self):
return self.original_stdout.fileno()
@contextmanager
def patch(self):
original_stdout = sys.stdout
sys.stdout = self
try:
yield
finally:
self.flush()
sys.stdout = original_stdout