Skip to content

Instantly share code, notes, and snippets.

@jerblack
Last active May 7, 2025 20:18
Show Gist options
  • Save jerblack/4b98ba48ed3fb1d9f7544d2b1a1be287 to your computer and use it in GitHub Desktop.
Save jerblack/4b98ba48ed3fb1d9f7544d2b1a1be287 to your computer and use it in GitHub Desktop.
Golang: Mirror all writes to stdout and stderr in program to log file
package main
import (
"fmt"
"io"
"log"
"os"
)
func main() {
fn := logOutput()
defer fn()
var words = "Hello\nDoctor\nName\nContinue\nYesterday\nTomorrow"
for i:=0 ; i < 10 ; i++ {
log.Println(i)
fmt.Println(i)
fmt.Println(words)
}
}
func logOutput() func() {
logfile := `logfile`
// open file read/write | create if not exist | clear file at open if exists
f, _ := os.OpenFile(logfile, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0666)
// save existing stdout | MultiWriter writes to saved stdout and file
out := os.Stdout
mw := io.MultiWriter(out, f)
// get pipe reader and writer | writes to pipe writer come out pipe reader
r, w, _ := os.Pipe()
// replace stdout,stderr with pipe writer | all writes to stdout, stderr will go through pipe instead (fmt.print, log)
os.Stdout = w
os.Stderr = w
// writes with log.Print should also write to mw
log.SetOutput(mw)
//create channel to control exit | will block until all copies are finished
exit := make(chan bool)
go func() {
// copy all reads from pipe to multiwriter, which writes to stdout and file
_,_ = io.Copy(mw, r)
// when r or w is closed copy will finish and true will be sent to channel
exit <- true
}()
// function to be deferred in main until program exits
return func() {
// close writer then block on exit channel | this will let mw finish writing before the program exits
_ = w.Close()
<-exit
// close file after all writes have finished
_ = f.Close()
}
}
@pvillela
Copy link

Extremely helpful!

@halshar
Copy link

halshar commented Sep 26, 2022

// save existing stdout | MultiWriter writes to saved stdout and file
out := os.Stdout
mw := io.MultiWriter(out, f)

why not use stdout directly instead of making a copy?

@theprantadutta
Copy link

thanks a lot, man.

@goodevilgenius
Copy link

This could definitely be used by a malicious actor.

  1. Be super secret spy people
  2. Make an open source library that lots of people use
  3. Wait for your enemies to use your library in their super secret software.
  4. Add code like this in an init function to your library and copy all of the output from your enemies' applications to your servers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment