package log import ( "bytes" "strings" "sync" ) type logTarget interface { Info(args ...interface{}) Warn(args ...interface{}) Error(args ...interface{}) } // logrusWriter can be used as the destination for a tool's std output and forwards // chunks between linebreaks to the logrus framework. This works around a problem // with using Entry().Writer() directly, since that doesn't support chunks // larger than 64K without linebreaks. // Implementation copied from https://github.com/sirupsen/logrus/issues/564 type logrusWriter struct { logger logTarget buffer bytes.Buffer mutex sync.Mutex } func (w *logrusWriter) Write(buffer []byte) (int, error) { w.mutex.Lock() defer w.mutex.Unlock() origLen := len(buffer) for { if len(buffer) == 0 { return origLen, nil } linebreakIndex := bytes.IndexByte(buffer, '\n') if linebreakIndex < 0 { w.buffer.Write(buffer) return origLen, nil } w.buffer.Write(buffer[:linebreakIndex]) w.alwaysFlush() buffer = buffer[linebreakIndex+1:] } } func (w *logrusWriter) alwaysFlush() { message := w.buffer.String() w.buffer.Reset() // Align level with underlying tool (like maven or npm) // This is to avoid confusion when maven or npm print errors or warnings which piper would print as "info" if strings.Contains(message, "ERROR") || strings.Contains(message, "ERR!") { w.logger.Error(message) } else if strings.Contains(message, "WARN") { w.logger.Warn(message) } else { w.logger.Info(message) } } func (w *logrusWriter) Flush() { w.mutex.Lock() defer w.mutex.Unlock() if w.buffer.Len() != 0 { w.alwaysFlush() } }