JuliaDocs/IOCapture.jl

Add a `pass_through` option

Closed this issue · 6 comments

I would like to have a tee option so that

c = IOCapture.capture(tee=true) do
     println("test")
     return 42
 end;

captures the output and value of the code block, but also still prints to the normal stdout and stderr (or combines stderr into stdout, I don't care about keeping them separate). What I do care about is that it should stream stdout as normal, while the function is running, as opposed to just dumping the captured output after the block finished running.

The option could be named something other than tee, of course, if that's too unix-jargony.

This seems like a good feature to have here. I would indeed call it something other than tee though, since that does feel a bit jargony.

I'm going to play around a little and see if I come up with something that works

Well, here's a start:

output = IOBuffer()
temp = IOBuffer()
buffer_redirect_task = @async begin
    write(temp, pipe)
    temp_data = take!(temp)
    write(output, temp_data)
    write(default_stdout, temp_data)
end

This seems to capture the data from the pipe while also passing it through the normal stdout.

Is this a good idea, or does this have the potential to block something or slow things down at a low level? If there's an expert on the IO internals that can sign off on this, I can easily build that into a full PR.

This might work, too, and avoid the allocation of temp_data?

output = IOBuffer()
temp = IOBuffer()
buffer_redirect_task = @async begin
    n_bytes = write(temp, pipe)
    seek(temp, 0)
    write(output, read(temp, n_bytes))
    seek(temp, 0)
    write(default_stdout, read(temp, n_bytes))
end

Ugh… neither of these actually works. I should have tested it on a longer-running calculation to start with. It seems like the writing to default_stdout gets buffered until the task ends. I've tried adding a flush(default_stdout), too.

Update: this one works better:

bufsize = 128
buffer = Vector{UInt8}(undef, bufsize)
buffer_redirect_task = @async begin
    while !eof(pipe)
        nbytes = readbytes!(pipe, buffer, bufsize)
        data = view(buffer, 1:nbytes)
        write(output, data)
        write(default_stdout, data)
    end
end