4
4
"bufio"
5
5
"io"
6
6
"runtime"
7
+ "strings"
7
8
)
8
9
9
10
// Writer at INFO level. See WriterLevel for details.
@@ -20,15 +21,18 @@ func (logger *Logger) WriterLevel(level Level) *io.PipeWriter {
20
21
return NewEntry (logger ).WriterLevel (level )
21
22
}
22
23
24
+ // Writer returns an io.Writer that writes to the logger at the info log level
23
25
func (entry * Entry ) Writer () * io.PipeWriter {
24
26
return entry .WriterLevel (InfoLevel )
25
27
}
26
28
29
+ // WriterLevel returns an io.Writer that writes to the logger at the given log level
27
30
func (entry * Entry ) WriterLevel (level Level ) * io.PipeWriter {
28
31
reader , writer := io .Pipe ()
29
32
30
33
var printFunc func (args ... interface {})
31
34
35
+ // Determine which log function to use based on the specified log level
32
36
switch level {
33
37
case TraceLevel :
34
38
printFunc = entry .Trace
@@ -48,23 +52,51 @@ func (entry *Entry) WriterLevel(level Level) *io.PipeWriter {
48
52
printFunc = entry .Print
49
53
}
50
54
55
+ // Start a new goroutine to scan the input and write it to the logger using the specified print function.
56
+ // It splits the input into chunks of up to 64KB to avoid buffer overflows.
51
57
go entry .writerScanner (reader , printFunc )
58
+
59
+ // Set a finalizer function to close the writer when it is garbage collected
52
60
runtime .SetFinalizer (writer , writerFinalizer )
53
61
54
62
return writer
55
63
}
56
64
65
+ // writerScanner scans the input from the reader and writes it to the logger
57
66
func (entry * Entry ) writerScanner (reader * io.PipeReader , printFunc func (args ... interface {})) {
58
67
scanner := bufio .NewScanner (reader )
68
+
69
+ // Set the buffer size to the maximum token size to avoid buffer overflows
70
+ scanner .Buffer (make ([]byte , bufio .MaxScanTokenSize ), bufio .MaxScanTokenSize )
71
+
72
+ // Define a split function to split the input into chunks of up to 64KB
73
+ chunkSize := 64 * 1024 // 64KB
74
+ splitFunc := func (data []byte , atEOF bool ) (int , []byte , error ) {
75
+ if len (data ) > chunkSize {
76
+ return chunkSize , data [:chunkSize ], nil
77
+ }
78
+
79
+ return len (data ), data , nil
80
+ }
81
+
82
+ //Use the custom split function to split the input
83
+ scanner .Split (splitFunc )
84
+
85
+ // Scan the input and write it to the logger using the specified print function
59
86
for scanner .Scan () {
60
- printFunc (scanner .Text ())
87
+ printFunc (strings . TrimRight ( scanner .Text (), " \r \n " ))
61
88
}
89
+
90
+ // If there was an error while scanning the input, log an error
62
91
if err := scanner .Err (); err != nil {
63
92
entry .Errorf ("Error while reading from Writer: %s" , err )
64
93
}
94
+
95
+ // Close the reader when we are done
65
96
reader .Close ()
66
97
}
67
98
99
+ // WriterFinalizer is a finalizer function that closes then given writer when it is garbage collected
68
100
func writerFinalizer (writer * io.PipeWriter ) {
69
101
writer .Close ()
70
102
}
0 commit comments