mirror of https://github.com/crytic/slither
Updated standard output capturing to optionally mirror to stdout/stderr (needed for outputting JSON to file, which retains output to console as well).
parent
4efe4b2fb5
commit
53a3bee4de
@ -0,0 +1,90 @@ |
||||
import io |
||||
import logging |
||||
import sys |
||||
|
||||
|
||||
class CapturingStringIO(io.StringIO): |
||||
""" |
||||
I/O implementation which captures output, and optionally mirrors it to the original I/O stream it replaces. |
||||
""" |
||||
def __init__(self, original_io=None): |
||||
super(CapturingStringIO, self).__init__() |
||||
self.original_io = original_io |
||||
|
||||
def write(self, s): |
||||
super().write(s) |
||||
if self.original_io: |
||||
self.original_io.write(s) |
||||
|
||||
|
||||
class StandardOutputCapture: |
||||
""" |
||||
Redirects and captures standard output/errors. |
||||
""" |
||||
original_stdout = None |
||||
original_stderr = None |
||||
original_logger_handlers = None |
||||
|
||||
@staticmethod |
||||
def enable(block_original=True): |
||||
""" |
||||
Redirects stdout and stderr to a capturable StringIO. |
||||
:param block_original: If True, blocks all output to the original stream. If False, duplicates output. |
||||
:return: None |
||||
""" |
||||
# Redirect stdout |
||||
if StandardOutputCapture.original_stdout is None: |
||||
StandardOutputCapture.original_stdout = sys.stdout |
||||
sys.stdout = CapturingStringIO(None if block_original else StandardOutputCapture.original_stdout) |
||||
|
||||
# Redirect stderr |
||||
if StandardOutputCapture.original_stderr is None: |
||||
StandardOutputCapture.original_stderr = sys.stderr |
||||
sys.stderr = CapturingStringIO(None if block_original else StandardOutputCapture.original_stderr) |
||||
|
||||
# Backup and swap root logger handlers |
||||
root_logger = logging.getLogger() |
||||
StandardOutputCapture.original_logger_handlers = root_logger.handlers |
||||
root_logger.handlers = [logging.StreamHandler(sys.stderr)] |
||||
|
||||
@staticmethod |
||||
def disable(): |
||||
""" |
||||
Disables redirection of stdout/stderr, if previously enabled. |
||||
:return: None |
||||
""" |
||||
# If we have a stdout backup, restore it. |
||||
if StandardOutputCapture.original_stdout is not None: |
||||
sys.stdout.close() |
||||
sys.stdout = StandardOutputCapture.original_stdout |
||||
StandardOutputCapture.original_stdout = None |
||||
|
||||
# If we have an stderr backup, restore it. |
||||
if StandardOutputCapture.original_stderr is not None: |
||||
sys.stderr.close() |
||||
sys.stderr = StandardOutputCapture.original_stderr |
||||
StandardOutputCapture.original_stderr = None |
||||
|
||||
# Restore our logging handlers |
||||
if StandardOutputCapture.original_logger_handlers is not None: |
||||
root_logger = logging.getLogger() |
||||
root_logger.handlers = StandardOutputCapture.original_logger_handlers |
||||
StandardOutputCapture.original_logger_handlers = None |
||||
|
||||
@staticmethod |
||||
def get_stdout_output(): |
||||
""" |
||||
Obtains the output from the currently set stdout |
||||
:return: Returns stdout output as a string |
||||
""" |
||||
sys.stdout.seek(0) |
||||
return sys.stdout.read() |
||||
|
||||
@staticmethod |
||||
def get_stderr_output(): |
||||
""" |
||||
Obtains the output from the currently set stderr |
||||
:return: Returns stderr output as a string |
||||
""" |
||||
sys.stderr.seek(0) |
||||
return sys.stderr.read() |
@ -1,67 +0,0 @@ |
||||
import io |
||||
import logging |
||||
import sys |
||||
|
||||
|
||||
class StandardOutputRedirect: |
||||
""" |
||||
Redirects and captures standard output/errors. |
||||
""" |
||||
original_stdout = None |
||||
original_stderr = None |
||||
|
||||
@staticmethod |
||||
def enable(): |
||||
""" |
||||
Redirects stdout and/or stderr to a captureable StringIO. |
||||
:param redirect_stdout: True if redirection is desired for stdout. |
||||
:param redirect_stderr: True if redirection is desired for stderr. |
||||
:return: None |
||||
""" |
||||
# Redirect stdout |
||||
if StandardOutputRedirect.original_stdout is None: |
||||
StandardOutputRedirect.original_stdout = sys.stdout |
||||
sys.stdout = io.StringIO() |
||||
|
||||
# Redirect stderr |
||||
if StandardOutputRedirect.original_stderr is None: |
||||
StandardOutputRedirect.original_stderr = sys.stderr |
||||
sys.stderr = io.StringIO() |
||||
root_logger = logging.getLogger() |
||||
root_logger.handlers = [logging.StreamHandler(sys.stderr)] |
||||
|
||||
@staticmethod |
||||
def disable(): |
||||
""" |
||||
Disables redirection of stdout/stderr, if previously enabled. |
||||
:return: None |
||||
""" |
||||
# If we have a stdout backup, restore it. |
||||
if StandardOutputRedirect.original_stdout is not None: |
||||
sys.stdout.close() |
||||
sys.stdout = StandardOutputRedirect.original_stdout |
||||
StandardOutputRedirect.original_stdout = None |
||||
|
||||
# If we have an stderr backup, restore it. |
||||
if StandardOutputRedirect.original_stderr is not None: |
||||
sys.stderr.close() |
||||
sys.stderr = StandardOutputRedirect.original_stderr |
||||
StandardOutputRedirect.original_stderr = None |
||||
|
||||
@staticmethod |
||||
def get_stdout_output(): |
||||
""" |
||||
Obtains the output from stdout |
||||
:return: Returns stdout output as a string |
||||
""" |
||||
sys.stdout.seek(0) |
||||
return sys.stdout.read() |
||||
|
||||
@staticmethod |
||||
def get_stderr_output(): |
||||
""" |
||||
Obtains the output from stdout |
||||
:return: Returns stdout output as a string |
||||
""" |
||||
sys.stderr.seek(0) |
||||
return sys.stderr.read() |
Loading…
Reference in new issue