Last active
June 27, 2023 11:43
-
-
Save SHi-ON/606e2f523045766b6771ceca45968d8b to your computer and use it in GitHub Desktop.
Python Logger class to Capture the feed coming from system stderr and stdout and write it to a file on disk and back to their respective buffer as well. Designed as a context manager, you can add the logging functionality and redirection to any Python script by just adding a line of code.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
import pathlib | |
import sys | |
from ml.common.const import LOG_DIR_PATH, ML_DIR | |
def create_log_file_path(file_path, root_dir=ML_DIR, log_dir=LOG_DIR_PATH): | |
path_parts = list(pathlib.Path(file_path).parts) | |
relative_path_parts = path_parts[path_parts.index(root_dir) + 1:] | |
log_file_path = pathlib.Path(log_dir, *relative_path_parts) | |
log_file_path = log_file_path.with_suffix('.log') | |
# Create the directories and the file itself | |
log_file_path.parent.mkdir(parents=True, exist_ok=True) | |
log_file_path.touch(exist_ok=True) | |
return log_file_path | |
def set_up_logs(file_path, mode='a', level=logging.INFO): | |
log_file_path = create_log_file_path(file_path) | |
logging_handlers = [logging.FileHandler(log_file_path, mode=mode), | |
logging.StreamHandler(sys.stdout)] | |
logging.basicConfig( | |
handlers=logging_handlers, | |
format='%(asctime)s %(name)s %(levelname)s %(message)s', | |
level=level | |
) | |
class OpenedFileHandler(logging.FileHandler): | |
def __init__(self, file_handle, filename, mode): | |
self.file_handle = file_handle | |
super(OpenedFileHandler, self).__init__(filename, mode) | |
def _open(self): | |
return self.file_handle | |
class StandardError: | |
def __init__(self, buffer_stderr, buffer_file): | |
self.buffer_stderr = buffer_stderr | |
self.buffer_file = buffer_file | |
def write(self, message): | |
self.buffer_stderr.write(message) | |
self.buffer_file.write(message) | |
class StandardOutput: | |
def __init__(self, buffer_stdout, buffer_file): | |
self.buffer_stdout = buffer_stdout | |
self.buffer_file = buffer_file | |
def write(self, message): | |
self.buffer_stdout.write(message) | |
self.buffer_file.write(message) | |
class Logger: | |
def __init__(self, file_path, mode='a', level=logging.INFO): | |
self.stdout_ = sys.stdout | |
self.stderr_ = sys.stderr | |
log_file_path = create_log_file_path(file_path) | |
self.file_ = open(log_file_path, mode=mode) | |
logging_handlers = [OpenedFileHandler(self.file_, log_file_path, | |
mode=mode), | |
logging.StreamHandler(sys.stdout)] | |
logging.basicConfig( | |
handlers=logging_handlers, | |
format='%(asctime)s %(name)s %(levelname)s %(message)s', | |
level=level | |
) | |
# Overrides write() method of stdout and stderr buffers | |
def write(self, message): | |
self.stdout_.write(message) | |
self.stderr_.write(message) | |
self.file_.write(message) | |
def flush(self): | |
pass | |
def __enter__(self): | |
sys.stdout = StandardOutput(self.stdout_, self.file_) | |
sys.stderr = StandardError(self.stderr_, self.file_) | |
def __exit__(self, exc_type, exc_val, exc_tb): | |
sys.stdout = self.stdout_ | |
sys.stderr = self.stderr_ | |
self.file_.close() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example of adding logger to your script: