Write to file and stdout

I have a number of println statements in a script. I know I can also do println(io,blah) to write to a file. When I do that, output no longer goes to stdout. Can I do both at once?


maybe just do it twice?

function myprintln(io, blah)
    println(io, blah)

This needs a lot more work to define a proper IO interface, but

struct Tee{TIO <: Tuple} <: IO

Tee(streams...) = Tee(streams)

function _do_tee(tee, f, xs...)
    for io in tee.streams
        f(io, xs...)

Base.write(tee::Tee, x) = _do_tee(tee, write, x)
Base.write(tee::Tee, x::Union{SubString{String},String}) = _do_tee(tee, write, x)

print(Tee(stdout, stderr), "will appear twice")

You may also consider using Logging module, it looks like it’s more natural. You can combine it with Tamas solution to simplify logger setup, and get something like

@info <some piece of code>

in a very customizable way (even with the possibility to turn it off completely).

Not sure whether the above package is still runnable.

Okay its not working.

Thanks for the suggestions everybody. I tried doing as @jling suggested which would have probably been fine in most cases. But I only need to do this if a boolean flag is set to true, which made that way a bit complicated and RegressionTables.jl also doesn’t work as nicely with this method.

What I ended up doing is having a single IOBuffer that all output is written to. After each section of my code, I check if the LOG_RESULTS is set to true and if it is then I additionally take from the IOBuffer to write to the output file like so

    println(logfile, String(take!(copy(myio))))

You could actually I guess just do this once at the end of the program but in my case I like having the results print as they are available so I do that at the end of each section.

The package LoggingExtras might help too (in particular, there’s a TeeLogger that looks relevant, although I haven’t used it).

1 Like

Is there any references out there on what other methods need to be implemented for a proper IO subtype?

Or maybe more importantly, under what circumstances would you expect this implementation to be insufficient?

There is no formal spec as far as I can tell, but the manual should be informative. Basic write may be fine, it is just that the implementation above is not heavily tested. FWIW, I can’t even recall why I defined two methods for Base.write.

1 Like