Skip to content

Instantly share code, notes, and snippets.

@CypherpunkSamurai
Forked from jerblack/tee.go
Created July 26, 2024 14:50
Show Gist options
  • Save CypherpunkSamurai/76ebcb1488cdb53db3b1e442dc086cd6 to your computer and use it in GitHub Desktop.
Save CypherpunkSamurai/76ebcb1488cdb53db3b1e442dc086cd6 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()
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment