# Write to file and stdout

**URL:** https://discourse.julialang.org/t/write-to-file-and-stdout/35042
**Category:** General Usage
**Tags:** question, io
**Created:** [February 23, 2020, 4:38am UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042 "2020-02-23T04:38:58Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)
#### Post date: [February 23, 2020, 4:38am UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/1 "2020-02-23T04:38:58Z")

</div>

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?

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [February 23, 2020, 4:51am UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/2 "2020-02-23T04:51:36Z")

</div>

maybe just do it twice?

```julia
function myprintln(io, blah)
    println(blah)
    println(io, blah)
end

```

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [February 23, 2020, 5:47am UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/3 "2020-02-23T05:47:21Z")

</div>

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

```julia
struct Tee{TIO <: Tuple} <: IO
    streams::TIO
end

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

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

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")

```

---

<div class="post-metadata">

### Author: ![Skoffer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skoffer/32/378_2.png) [@Skoffer](https://discourse.julialang.org/u/Skoffer)
#### Post date: [February 23, 2020, 8:38am UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/4 "2020-02-23T08:38:33Z")

</div>

You may also consider using [Logging](https://docs.julialang.org/en/v1/stdlib/Logging/) module, it looks like it’s more natural. You can combine it with Tamas solution to simplify logger setup, and get something like

```julia
@info <some piece of code>

```

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

---

<div class="post-metadata">

### Author: ![innerlee](https://avatars.discourse-cdn.com/v4/letter/i/b19c9b/32.png) [@innerlee](https://discourse.julialang.org/u/innerlee)
#### Post date: [February 23, 2020, 1:32pm UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/5 "2020-02-23T13:32:16Z")

</div>

> **[GitHub - innerlee/PrintLog.jl: An incredibly simple logger! All it does is to...](https://github.com/innerlee/PrintLog.jl)**
>
> An incredibly simple logger! All it does is to log all outputs of \`print\` and \`println\` into a file. - GitHub - innerlee/PrintLog.jl: An incredibly simple logger! All it does is to log all outputs ...

Not sure whether the above package is still runnable.

---

<div class="post-metadata">

### Author: ![innerlee](https://avatars.discourse-cdn.com/v4/letter/i/b19c9b/32.png) [@innerlee](https://discourse.julialang.org/u/innerlee)
#### Post date: [February 23, 2020, 2:11pm UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/6 "2020-02-23T14:11:59Z")

</div>

Okay its not working.

---

<div class="post-metadata">

### Author: ![tbeason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tbeason/32/15898_2.png) [@tbeason](https://discourse.julialang.org/u/tbeason)
#### Post date: [February 23, 2020, 7:46pm UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/7 "2020-02-23T19:46:21Z")

</div>

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

```julia
if LOG_RESULTS
    println(logfile, String(take!(copy(myio))))
end
println(String(take!(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.

---

<div class="post-metadata">

### Author: ![ericphanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ericphanson/32/215186_2.png) [@ericphanson](https://discourse.julialang.org/u/ericphanson)
#### Post date: [February 23, 2020, 11:18pm UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/8 "2020-02-23T23:18:16Z")

</div>

The package [LoggingExtras](https://github.com/oxinabox/LoggingExtras.jl) might help too (in particular, there’s a `TeeLogger` that looks relevant, although I haven’t used it).

---

<div class="post-metadata">

### Author: ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)
#### Post date: [April 21, 2022, 4:15pm UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/9 "2022-04-21T16:15:27Z")

</div>

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?

---

<div class="post-metadata">

### Author: ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)
#### Post date: [April 22, 2022, 9:17am UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/10 "2022-04-22T09:17:56Z")

</div>

There is no formal spec as far as I can tell, but the [manual](https://docs.julialang.org/en/v1/manual/networking-and-streams/) 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`.

---

<div class="post-metadata">

### Author: ![tfiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tfiers/32/32427_2.png) [@tfiers](https://discourse.julialang.org/u/tfiers)
#### Post date: [January 12, 2023, 12:51pm UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/11 "2023-01-12T12:51:49Z")

</div>

> [@Mason](#):
>
> under what circumstances would you expect this implementation to be insufficient

One use case where the above doesn’t work: using Tee as the output stream in `run(pipeline(command, tee))`

I’ve tried some patches\*, but couldn’t get it to work yet

\*namely

- adding `Vector{UInt8}` to the type union here:

> [@Tamas\_Papp](#):
>
> `Base.write(tee::Tee, x::Union{SubString{String},String}) = _do_tee(tee, write, x)`

- defining

```julia
Base.write(to::Tee, from::IO) = invoke(write, Tuple{IO,IO}, to, from)

```

---

<div class="post-metadata">

### Author: ![tfiers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tfiers/32/32427_2.png) [@tfiers](https://discourse.julialang.org/u/tfiers)
#### Post date: [January 13, 2023, 12:41pm UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/12 "2023-01-13T12:41:29Z")

</div>

(For reference and for anyone stumbling upon this: I solved my task – namely to capture a subprocess’s output but also to live-print it to stdout; not via a Tee but as follows:

```julia
buf = IOBuffer()
pos = 0
process = run(pipeline(cmd, buf), wait=false)
while process_running(process)
    sleep(0.1)
    seek(buf, pos)
    new = read(buf, String)
    print(new)
    pos += sizeof(new)
end
output = String(take!(buf))

```

)

---

<div class="post-metadata">

### Author: ![fonsp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fonsp/32/222349_2.png) [@fonsp](https://discourse.julialang.org/u/fonsp)
#### Post date: [May 23, 2024, 8:12am UTC](https://discourse.julialang.org/t/write-to-file-and-stdout/35042/13 "2024-05-23T08:12:36Z")

</div>

You can also use `Base.BufferStream` for this, which is a fully implemented `IO` type (and it [might be public API at some point](https://github.com/fonsp/Pluto.jl/issues/2910#issuecomment-2097054795)).

```julia
function tee_io(captures...)
	bs = Base.BufferStream()

	t = @async begin
		while !eof(bs)
			data = readavailable(bs)
			isempty(data) && continue

			for s in captures
				write(s, data)
			end
		end
	end

	function closeme()
		close(bs)
		wait(t)
	end

	return (io=bs, close=closeme)
end

```

Example use, tee’ing the same data into stdout, stderr and into a buffer (created by `Base.sprint`):

```julia-repl
julia> sprint() do buffer
               
               tee = tee_io(stdout, stderr, buffer)

               # use the tee
               println(tee.io, "Hello!")
               show(tee.io, "text/plain", rand(4))
               println(tee.io)

               # close it
               tee.close()
       end
Hello!
4-element Vector{Float64}:
 0.6197851577079866
 0.11502872199346159
 0.09949018487645467
 0.35495614153953925
Hello!
4-element Vector{Float64}:
 0.6197851577079866
 0.11502872199346159
 0.09949018487645467
 0.35495614153953925
"Hello!\n4-element Vector{Float64}:\n 0.6197851577079866\n 0.11502872199346159\n 0.09949018487645467\n 0.35495614153953925\n"

```
