github.com/YousefHaggyHeroku/pack@v1.5.5/internal/logging/log_writer.go (about) 1 package logging 2 3 import ( 4 "fmt" 5 "io" 6 "os" 7 "regexp" 8 "sync" 9 "time" 10 11 "github.com/heroku/color" 12 ) 13 14 // LogWriter is a writer used for logs 15 type LogWriter struct { 16 sync.Mutex 17 out io.Writer 18 clock func() time.Time 19 wantTime bool 20 wantNoColor bool 21 } 22 23 var colorCodeMatcher = regexp.MustCompile(`\x1b\[[0-9;]*m`) 24 25 // NewLogWriter creates a LogWriter 26 func NewLogWriter(writer io.Writer, clock func() time.Time, wantTime bool) *LogWriter { 27 wantNoColor := !color.Enabled() 28 return &LogWriter{ 29 out: writer, 30 clock: clock, 31 wantTime: wantTime, 32 wantNoColor: wantNoColor, 33 } 34 } 35 36 // Write writes a message prepended by the time to the set io.Writer 37 func (tw *LogWriter) Write(buf []byte) (n int, err error) { 38 tw.Lock() 39 defer tw.Unlock() 40 41 length := len(buf) 42 if tw.wantNoColor { 43 buf = stripColor(buf) 44 } 45 46 prefix := "" 47 if tw.wantTime { 48 prefix = fmt.Sprintf("%s ", tw.clock().Format(timeFmt)) 49 } 50 51 _, err = fmt.Fprintf(tw.out, "%s%s", prefix, buf) 52 return length, err 53 } 54 55 // Fd returns the file descriptor of the writer. This is used to ensure it is a Console, and can therefore display streams of text 56 func (tw *LogWriter) Fd() uintptr { 57 tw.Lock() 58 defer tw.Unlock() 59 60 file, ok := tw.out.(*os.File) 61 if ok { 62 return file.Fd() 63 } 64 65 return 0 66 } 67 68 // Remove all ANSI color information. 69 func stripColor(b []byte) []byte { 70 return colorCodeMatcher.ReplaceAll(b, []byte("")) 71 }