Skip to content

Commit

Permalink
Add run_logged_shell_subprocess to track subprocess output/errors
Browse files Browse the repository at this point in the history
  • Loading branch information
Justin Campbell committed Sep 15, 2020
1 parent 2c85678 commit 74653c4
Showing 1 changed file with 71 additions and 5 deletions.
76 changes: 71 additions & 5 deletions utils/venv-manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,19 @@
$ venv-manager.py reset
"""

import os, logging, argparse, pathlib
from pathlib import Path
import os, logging, argparse, subprocess


################################################################################
# Configuration
################################################################################

# Set virtual environment path
WEBQUEUE2_DIR = pathlib.Path(__file__).parent.parent
API_DIR = pathlib.Path(WEBQUEUE2_DIR, "api")
VENV_DIR = pathlib.Path(API_DIR, 'venv')
WEBQUEUE2_DIR = Path(__file__).parent.parent
API_DIR = Path(WEBQUEUE2_DIR, "api")
VENV_NAME = "venv"
VENV_DIR = Path(API_DIR, VENV_NAME)


# Configure the logger
Expand All @@ -38,7 +40,7 @@
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(log_formatter)

log_file_path = pathlib.Path(WEBQUEUE2_DIR, "utils", f'{logger_name}.log')
log_file_path = Path(WEBQUEUE2_DIR, "utils", f'{logger_name}.log')
file_handler = logging.FileHandler(log_file_path)
file_handler.setFormatter(log_formatter)

Expand All @@ -65,7 +67,71 @@ def get_args() -> argparse.Namespace:
)
return parser.parse_args()

command = f"cd {API_DIR} && python3 -m venv {VENV_NAME}"
def run_logged_shell_subprocess(command: str, timeout: int = 10) -> int:
"""Executes a shell command using subprocess with logging.
stderr is redirected to stdout and stdout is pipped to logger.
If the subprocess raises an exception, the exception is logged as critical.
Example:
Running a successful command:
run_logged_shell_subprocess(command="pwd")
Returns 0
Running an unsuccessful command with a 20 second timeout:
run_logged_shell_subprocess(command="pwd", timeout=20)
Returns 1
Args:
command (str): The command to run
timeout (int): The number of seconds to wait for a program before killing it
Returns:
int: The return code of the subprocess
"""
logger.debug(f"Entering subprocess for '{command}'")
with subprocess.Popen(command,\
stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True, text=True)\
as logged_shell_process:

subprocess_log_prefix = f"(PID: {logged_shell_process.pid})"

try:
# Convert combined stdout and stderr stream to list of strings
process_output_stream, _ = logged_shell_process.communicate(timeout=timeout)
process_output_lines = process_output_stream.split("\n")
# Remove last entry in process_output_lines because it is always empty
process_output_lines.pop(-1)

for line in process_output_lines:
logger.debug(f"{subprocess_log_prefix}: {line}")
except Exception as exception:
logger.critical(str(exception))
return logged_shell_process.returncode
else:
if logged_shell_process.returncode != 0:
logger.debug(f"Subprocess exitied with a return code of {logged_shell_process.returncode}")
return logged_shell_process.returncode
elif logged_shell_process.returncode == 0:
logger.info(f"Subprocess for '{command}' completed successfuly")
return logged_shell_process.returncode
finally:
logger.debug(f"Exiting subprocess for '{command}''")





if __name__ == "__main__":
args = get_args()
action = args.action

if action == "create":
exit(create_environment())
elif action == "delete":
exit(delete_environment())
elif action == "reset":
exit(reset_environment())
else:
logger.critical(f'Invalid argument {action}')

0 comments on commit 74653c4

Please sign in to comment.