Capturing available data written to redirected STDOUT and/or STDERR

2022 update!

Now there’s Base.redirect_stdio, which, according to the name, should be able to redirect the input/output streams to… other streams, I guess. Since IOBuffer is “an in-memory I/O stream” (so basically an IOStream, but in-memory), I assumed it was possible to redirect output to an IOBuffer:

buf_stdout, buf_stderr = IOBuffer(), IOBuffer()
redirect_stdio(stdout=buf_stdout, stderr=buf_stderr, stdin=devnull) do
    @info "Hello!"
end

However, this doesn’t work:

MethodError: no method matching (::Base.RedirectStdStream)(::IOBuffer)
  Closest candidates are:
    (::Base.RedirectStdStream)() at stream.jl:1254
    (::Base.RedirectStdStream)(::Union{IOStream, Base.LibuvStream}) at stream.jl:1222
    (::Base.RedirectStdStream)(::Function, ::Any) at stream.jl:1417
    ...
  Stacktrace:
    [1] redirect_stdio(; stdin::Base.DevNull, stderr::IOBuffer, stdout::IOBuffer)
      @ Base ./stream.jl:1315
    [2] redirect_stdio(f::var"#9#11"{Symbol, Symbol, Matrix{Float64}}; stdin::Base.DevNull, stderr::IOBuffer, stdout::IOBuffer)
      @ Base ./stream.jl:1405
    ...

So apparently, IOBuffer, being “an in-memory I/O stream”, is actually not a proper IOStream, since it’s not possible to redirect_stdio to it.

There’s an issue about this, but it’s been open since 2015, and it doesn’t look like there’s a generally accepted solution…