github.com/openshift/installer@v1.4.17/pkg/lineprinter/lineprinter.go (about) 1 // Package lineprinter wraps a Print implementation to provide an io.WriteCloser. 2 package lineprinter 3 4 import ( 5 "bytes" 6 "io" 7 "sync" 8 ) 9 10 // Print is a type that can hold fmt.Print and other implementations 11 // which match that signature. For example, you can use: 12 // 13 // trimmer := &lineprinter.Trimmer{WrappedPrint: logrus.StandardLogger().Debug} 14 // linePrinter := &linePrinter{Print: trimmer.Print} 15 // 16 // to connect the line printer to logrus at the debug level. 17 type Print func(args ...interface{}) 18 19 // LinePrinter is an io.WriteCloser that buffers written bytes. 20 // During each Write, newline-terminated lines are removed from the 21 // buffer and passed to Print. On Close, any content remaining in the 22 // buffer is also passed to Print. 23 // 24 // One use-case is connecting a subprocess's standard streams to a 25 // logger: 26 // 27 // linePrinter := &linePrinter{ 28 // Print: &Trimmer{WrappedPrint: logrus.StandardLogger().Debug}.Print, 29 // } 30 // defer linePrinter.Close() 31 // cmd := exec.Command(...) 32 // cmd.Stdout = linePrinter 33 // 34 // LinePrinter buffers the subcommand's byte stream and splits it into 35 // lines for the logger. Sometimes we might have a partial line 36 // written to the buffer. We don't want to push that partial line into 37 // the logs if the next read attempt will pull in the remainder of the 38 // line. But we do want to push that partial line into the logs if there 39 // will never be a next read. So LinePrinter.Write pushes any 40 // complete lines to the wrapped printer, and LinePrinter.Close pushes 41 // any remaining partial line. 42 type LinePrinter struct { 43 buf bytes.Buffer 44 Print Print 45 46 sync.Mutex 47 } 48 49 // Write writes len(p) bytes from p to an internal buffer. Then it 50 // retrieves any newline-terminated lines from the internal buffer and 51 // prints them with lp.Print. Partial lines are left in the internal 52 // buffer. 53 func (lp *LinePrinter) Write(p []byte) (int, error) { 54 lp.Lock() 55 defer lp.Unlock() 56 n, err := lp.buf.Write(p) 57 if err != nil { 58 return n, err 59 } 60 61 for { 62 line, err := lp.buf.ReadString(byte('\n')) 63 if err == io.EOF { 64 _, err = lp.buf.Write([]byte(line)) 65 return n, err 66 } else if err != nil { 67 return n, err 68 } 69 70 lp.Print(line) 71 } 72 } 73 74 // Close prints anything that remains in the buffer. 75 func (lp *LinePrinter) Close() error { 76 lp.Lock() 77 defer lp.Unlock() 78 line := lp.buf.String() 79 if len(line) > 0 { 80 lp.Print(line) 81 } 82 return nil 83 }