In a previous blog post I pondered whether it may be possible to redirect STDERR to an IOBuffer so that the output can be handled in a controlled way e.g. written to a log file. It turns out that it’s not quite that simple, but capturing output can still be achieved easily with a few more lines of code.
The noteworthy functions here are the redirect_std* family of functions. These functions redirect their respective handles to a new pipe and return a read and write handle for said pipe.
Below is an example of capturing output to STDOUT.
(outRead, outWrite) = redirect_stdout() print("Test") print("ing") close(outWrite) data = readavailable(outRead) close(outRead)
At the end of execution, the variable “data” will contain the string ‘Testing’.
(As seen on line 6, it’s advisable to close the write handle before trying to read from the pipe, as this will ensure that any buffered writes are flushed and available for reading.)
If you need to write to the original output stream after redirecting and capturing data, you’ll first need to create a copy of the original handle and restore it later. For example:
originalSTDOUT = STDOUT (outRead, outWrite) = redirect_stdout() print("Test") print("ing") close(outWrite) data = readavailable(outRead) close(outRead) redirect_stdout(originalSTDOUT) print(data)
Line 1 is where the original handle is copied; line 14 is where it’s restored. The print on line 16 will therefore write to the original STDOUT (e.g. console window, browser, etc) instead of the outWrite pipe.
This technique is particularly useful when applied to STDERR, as it can be used to write errors to a log file. The process is the same, but instead using functions applicable to STDERR. Below is a slightly different example:
(errorRead, errorWrite) = redirect_stderr() atexit(function () close(errorWrite) errors = readavailable(errorRead) close(errorRead) logfile = open("errors.log", "a") write(logfile, errors) close(logfile) end)
atexit registers a function to be called when the program execution ends for whatever reason (fatal error, user called the quit function, etc). The code between lines 4 and 8 is similar to the STDOUT example – and code as been added at lines 10 to 12 to log the captured error(s) to a file.