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