github.com/jaylevin/jenkins-library@v1.230.4/pkg/log/writer.go (about) 1 package log 2 3 import ( 4 "bytes" 5 "strings" 6 "sync" 7 ) 8 9 type logTarget interface { 10 Info(args ...interface{}) 11 Warn(args ...interface{}) 12 Error(args ...interface{}) 13 } 14 15 // logrusWriter can be used as the destination for a tool's std output and forwards 16 // chunks between linebreaks to the logrus framework. This works around a problem 17 // with using Entry().Writer() directly, since that doesn't support chunks 18 // larger than 64K without linebreaks. 19 // Implementation copied from https://github.com/sirupsen/logrus/issues/564 20 type logrusWriter struct { 21 logger logTarget 22 buffer bytes.Buffer 23 mutex sync.Mutex 24 } 25 26 func (w *logrusWriter) Write(buffer []byte) (int, error) { 27 w.mutex.Lock() 28 defer w.mutex.Unlock() 29 30 origLen := len(buffer) 31 for { 32 if len(buffer) == 0 { 33 return origLen, nil 34 } 35 linebreakIndex := bytes.IndexByte(buffer, '\n') 36 if linebreakIndex < 0 { 37 w.buffer.Write(buffer) 38 return origLen, nil 39 } 40 41 w.buffer.Write(buffer[:linebreakIndex]) 42 w.alwaysFlush() 43 buffer = buffer[linebreakIndex+1:] 44 } 45 } 46 47 func (w *logrusWriter) alwaysFlush() { 48 message := w.buffer.String() 49 w.buffer.Reset() 50 // Align level with underlying tool (like maven or npm) 51 // This is to avoid confusion when maven or npm print errors or warnings which piper would print as "info" 52 if strings.Contains(message, "ERROR") || strings.Contains(message, "ERR!") { 53 w.logger.Error(message) 54 } else if strings.Contains(message, "WARN") { 55 w.logger.Warn(message) 56 } else { 57 w.logger.Info(message) 58 } 59 } 60 61 func (w *logrusWriter) Flush() { 62 w.mutex.Lock() 63 defer w.mutex.Unlock() 64 65 if w.buffer.Len() != 0 { 66 w.alwaysFlush() 67 } 68 }